Generate Random Strings in Go
Random strings are useful for temporary identifiers, test data, filenames, invitation codes, and security-sensitive tokens. Go offers different random-number sources, and choosing the correct one matters.
1. math/rand for Non-Security Uses
For simulations, test fixtures, randomized UI behavior, or other cases where predictability is not a security problem, math/rand is appropriate.
With modern Go, create an explicit generator when you need independent pseudo-random state:
package main
import (
"fmt"
"math/rand"
)
const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
func GenerateRandomString(r *rand.Rand, length int) string {
result := make([]byte, length)
for i := range result {
result[i] = alphabet[r.Intn(len(alphabet))]
}
return string(result)
}
func main() {
r := rand.New(rand.NewSource(42))
fmt.Println(GenerateRandomString(r, 10))
}A fixed seed is useful for reproducible tests. Do not use math/rand for secrets, session tokens, password-reset tokens, or other authentication material.
2. crypto/rand for Security-Sensitive Strings
Use crypto/rand when values must be unpredictable. This implementation selects characters without modulo bias:
package main
import (
"crypto/rand"
"fmt"
"math/big"
)
const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
func GenerateSecureRandomString(length int) (string, error) {
if length < 0 {
return "", fmt.Errorf("length must be non-negative")
}
result := make([]byte, length)
max := big.NewInt(int64(len(alphabet)))
for i := range result {
n, err := rand.Int(rand.Reader, max)
if err != nil {
return "", err
}
result[i] = alphabet[n.Int64()]
}
return string(result), nil
}
func main() {
value, err := GenerateSecureRandomString(32)
if err != nil {
panic(err)
}
fmt.Println(value)
}For tokens that do not need a custom alphabet, generating random bytes and encoding them is often simpler and faster:
func GenerateToken(byteLength int) (string, error) {
buf := make([]byte, byteLength)
if _, err := rand.Read(buf); err != nil {
return "", err
}
return base64.RawURLEncoding.EncodeToString(buf), nil
}RawURLEncoding is convenient for tokens placed in URLs because it avoids +, /, and padding characters.
3. UUIDs for Standard Identifiers
If you need a conventional unique identifier rather than an arbitrary random string, a UUID can be a good fit:
package main
import (
"fmt"
"github.com/google/uuid"
)
func main() {
id := uuid.New()
fmt.Println(id.String())
}UUIDs are common for database identifiers and distributed systems, but they are not automatically a replacement for high-entropy security tokens.
Which Option Should You Use?
| Method | Good for | Avoid for |
|---|---|---|
math/rand |
simulations, tests, non-secret randomization | authentication and secrets |
crypto/rand |
tokens, reset links, secret identifiers | cases that need deterministic output |
| UUID | standardized unique identifiers | arbitrary-format secret tokens |
Conclusion
Use math/rand when reproducibility or lightweight pseudo-randomness is enough. Use crypto/rand whenever unpredictability is part of the security requirement. Use UUIDs when you need a standardized identifier format rather than a general-purpose random string.