Generate Random Numbers in Go
Table of Contents
Random numbers are useful for games, simulations, shuffling, sampling, and test data. In Go 1.22+, the recommended package for non-secure randomness is math/rand/v2, which provides modern generators and a clearer API. For anything security-sensitive (tokens, passwords, keys), use crypto/rand instead. 🚀
What Is Random Number Generation in Go? #
math/rand/v2 uses pseudo-random number generators (PRNGs). PRNGs are fast and repeatable, but they are deterministic once the internal state is known. That makes them great for simulations and games, and a bad fit for security. If you start a generator with the same seed, you will get the same sequence again, which is handy for tests.
When to Use Random Numbers #
- Simulations, games, shuffling, sampling: use
math/rand/v2 - Security-sensitive values (tokens, passwords, keys): use
crypto/rand - Repeatable tests: use a fixed seed with a custom
*rand.Rand
How to Generate Random Numbers in Go (math/rand/v2) #
Full working example using math/rand/v2:
package main
import (
"fmt"
"math/rand/v2"
)
func randIntRange(min, max int) int {
if max <= min {
panic("max must be greater than min")
}
return min + rand.IntN(max-min)
}
func randFloatRange(min, max float64) float64 {
if max <= min {
panic("max must be greater than min")
}
return min + rand.Float64()*(max-min)
}
func main() {
fmt.Println("any int:", rand.Int())
fmt.Printf("any float64: %.6f\n", rand.Float64())
fmt.Println("int in [5, 10):", randIntRange(5, 10))
fmt.Printf("float64 in [2.4, 3.2): %.6f\n", randFloatRange(2.4, 3.2))
}
Example output:
any int: 5696350091330895579
any float64: 0.764513
int in [5, 10): 6
float64 in [2.4, 3.2): 3.142109
How it works:
rand.Intreturns a non-negative int.rand.Float64returns a float in[0.0, 1.0).- Int range:
min + rand.IntN(max-min)produces[min, max)usingrand.IntN. - Float range:
min + rand.Float64()*(max-min)produces[min, max)usingrand.Float64.
Modern Go Features (Go 1.22+): math/rand/v2 #
The new math/rand/v2 package is recommended for new code because:
- It includes modern generators like PCG and ChaCha8 (still not cryptographically secure).
- It adds clearer range helpers such as
IntN,Int64N,UintN, and the genericN. - It removes the old global seeding pattern; if you want repeatable output, create your own generator with
rand.New.
PCG stands for Permuted Congruential Generator. It is a fast PRNG family with good statistical quality for simulations, games, and tests.
Reproducible random numbers for tests #
package main
import (
"fmt"
"math/rand/v2"
)
func main() {
r := rand.New(rand.NewPCG(1, 2))
fmt.Println(r.IntN(100))
fmt.Println(r.IntN(100))
}
Use a fixed seed for tests so results stay stable.
This example builds a local generator with rand.New and rand.NewPCG, which returns a *rand.Rand you can pass around.
Secure Random Numbers with crypto/rand #
For tokens, passwords, and security-sensitive data, use crypto/rand. It reads from the operating system’s cryptographically secure random source.
package main
import (
"crypto/rand"
"fmt"
"math/big"
)
func secureIntRange(min, max int64) (int64, error) {
if max <= min {
return 0, fmt.Errorf("max must be greater than min")
}
n, err := rand.Int(rand.Reader, big.NewInt(max-min))
if err != nil {
return 0, err
}
return min + n.Int64(), nil
}
func main() {
v, err := secureIntRange(1000, 10000)
if err != nil {
panic(err)
}
fmt.Println("secure int in [1000, 10000):", v)
}
Like math/rand/v2, crypto/rand.Int treats the upper bound as exclusive, so the range is [min, max).
This uses crypto/rand.Int with rand.Reader and big.NewInt to set the upper bound.
Gotchas #
math/rand/v2is not for secrets; usecrypto/randfor tokens and passwords.- Range helpers like
IntNexpectmax > min; otherwise you will panic onIntN(0). - A
*rand.Randis not safe for concurrent use without synchronization.
Best Practices #
- Validate ranges so
max > minand avoid passing 0 toIntN. - Use
math/rand/v2for simulations and tests, not for secrets. - Create a local
*rand.Randwithrand.NewPCGwhen you need reproducible output. - The top-level functions are concurrency-safe, but a
*rand.Randneeds synchronization if shared.
Related Topics #
- Generate random strings in Go: Build IDs, salts, and test data.
- Generate UUIDs in Go: Unique identifiers for records and requests.
- Int min/max in Go: Keep ranges and bounds correct.
- Float64 min/max in Go: Safe bounds for float ranges.
- Round floats in Go: Format and round random floats.
Tested with Go 1.25+ | Last verified: December 2025
Happy coding! 🎉