Question

How to Generate a Random String of Fixed Length in Go

gostringrandom

Question

I want to generate a random string of a fixed length in Go using only alphabetic characters (A-Z and a-z), with no digits or symbols. What is the simplest and fastest way to do this?

Short Answer

By the end of this page, you will understand how to generate random strings in Go, how to limit the characters to uppercase and lowercase letters only, and when to choose a simple approach versus a more secure one.

Concept

Random string generation in Go usually means:

  • choosing a set of allowed characters
  • picking characters from that set at random
  • repeating until the string reaches the required length

For this question, the allowed character set is only letters:

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

The core idea is that a random string is built one character at a time. For each position in the string, your program randomly selects one character from the allowed alphabet.

This matters in real programming because random strings are often used for:

  • temporary identifiers
  • invite codes
  • test data
  • filenames
  • mock tokens

In Go, there are two common ways to generate random values:

  • math/rand for general-purpose pseudo-random values
  • crypto/rand for security-sensitive randomness

If you only want a simple random-looking string for testing or non-sensitive use, math/rand is often enough. If the string is used for passwords, reset tokens, API secrets, or anything security-related, use crypto/rand instead.

A fixed-length random string is not about generating one random word. It is about repeatedly sampling from a known alphabet until you have enough characters.

Mental Model

Imagine you have a bag containing 52 tiles:

  • 26 lowercase letters
  • 26 uppercase letters

To build a random string of length 8:

  1. reach into the bag
  2. pick one tile
  3. write it down
  4. put the tile back
  5. repeat 8 times

That is exactly what the code does. The string length tells you how many picks to make, and the alphabet string is the bag of available characters.

Take Quiz

Syntax and Examples

Basic approach with math/rand

package main

import (
	"fmt"
	"math/rand"
	"time"
)

const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

func randomString(n int) string {
	rand.Seed(time.Now().UnixNano())
	b := make([]byte, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func main() {
	fmt.Println(randomString(10))
}

How it works

  • letters stores all allowed characters.
  • make([]byte, n) creates space for n characters.
  • rand.Intn(len(letters)) picks a random index.
  • Each byte in b is filled with one random letter.
  • string(b) converts the byte slice into a Go string.

Better structure: seed once

Seeding inside the function is simple, but in real code it is better to seed the random generator once.

package main

import (
	"fmt"
	"math/rand"
	"time"
)

const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

func randomString(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func main() {
	rand.Seed(time.Now().UnixNano())
	fmt.Println(randomString(8))
	fmt.Println(randomString(8))
}

This avoids reseeding on every call.

Secure version with crypto/rand

Use this if the randomness matters for security.

package main

import (
	"crypto/rand"
	"fmt"
	"math/big"
)

const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

func secureRandomString(n int) (string, error) {
	b := make([]byte, n)
	for i := range b {
		n, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
		if err != nil {
			return "", err
		}
		b[i] = letters[n.Int64()]
	}
	return string(b), nil
}

func main() {
	s, err := secureRandomString(10)
	if err != nil {
		panic(err)
	}
	fmt.Println(s)
}

This version is slower than math/rand, but appropriate for secrets and tokens.

Step by Step Execution

Consider this function:

const letters = "abcXYZ"

func randomString(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

If we call:

rand.Seed(1)
fmt.Println(randomString(4))

Here is the step-by-step idea:

  1. letters contains 6 possible characters:

    • a
    • b
    • c
    • X
    • Y
    • Z
  2. make([]byte, 4) creates a byte slice with space for 4 characters.

  3. The loop runs 4 times, once for each position.

  4. On each loop:

    • rand.Intn(6) returns a number from 0 to 5
    • that number is used as an index into letters
    • the selected letter is stored in b[i]
  5. Example sequence of chosen indexes:

2, 5, 0, 4
  1. That would map to:
c, Z, a, Y
  1. The byte slice becomes:
['c', 'Z', 'a', 'Y']
  1. string(b) converts it into:
"cZaY"

The exact output changes depending on the random values, but the process is always the same: random index -> character lookup -> build string.

Real World Use Cases

Random fixed-length letter strings are useful in many situations:

  • Test data generation
    • Create fake usernames like AbCdEf.
  • Temporary file labels
    • Generate readable suffixes for filenames.
  • Invite or referral codes
    • If security is not critical, a short random letter code may be enough.
  • Mock API responses
    • Simulate IDs or labels in development.
  • Games and simulations
    • Generate random names, room codes, or labels.

If the string protects access to something important, do not use math/rand. Use crypto/rand instead.

Take Quiz

Real Codebase Usage

In real projects, developers usually wrap this logic in a small helper function so it can be reused across the codebase.

Common patterns include:

Validation

Check that the requested length is valid.

func randomString(n int) string {
	if n <= 0 {
		return ""
	}

	b := make([]byte, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

Early return

Guard clauses keep the function simple.

if n <= 0 {
	return ""
}

Reusable alphabet configuration

Developers often make the allowed characters configurable.

func randomFromCharset(n int, charset string) string {
	if n <= 0 || len(charset) == 0 {
		return ""
	}

	b := make([]byte, n)
	for i := range b {
		b[i] = charset[rand.Intn(len(charset))]
	}
	return string(b)
}

Error handling for secure randomness

When using crypto/rand, return an error instead of hiding failures.

func secureRandomString(n int) (string, error) {
	// return error if crypto random generation fails
	return "", nil
}

Utility packages

In larger codebases, this logic often lives in packages such as:

  • util
  • internal/random
  • pkg/helpers

The main goal is to avoid rewriting the same loop in many places.

Common Mistakes

1. Seeding every time the function is called

This is a very common beginner mistake.

Problematic code

func randomString(n int) string {
	rand.Seed(time.Now().UnixNano())
	b := make([]byte, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

Why it is a problem

  • It repeats work unnecessarily.
  • Calls made very close together can behave poorly.
  • Seeding should usually happen once.

Better

func main() {
	rand.Seed(time.Now().UnixNano())
	fmt.Println(randomString(8))
}

2. Using math/rand for secrets

Broken choice

// Not suitable for password reset tokens
code := randomString(32)

Why it is a problem

math/rand is predictable compared with cryptographic randomness.

Better

Use crypto/rand for anything security-sensitive.

3. Forgetting to restrict the character set

If you want letters only, your alphabet must contain only letters.

Wrong idea

const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

This includes digits, so the result is not letters-only.

4. Not handling zero or negative lengths

Risky code

func randomString(n int) string {
	b := make([]byte, n)
	return string(b)
}

Negative values will panic when creating the slice.

Better

func randomString(n int) string {
	if n <= 0 {
		return ""
	}
	b := make([]byte, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

5. Confusing bytes and runes

For plain English letters, bytes are fine because each character is one byte in UTF-8. If you later use non-ASCII characters, the approach may need to change.

Comparisons

ApproachBest forFastSecureNotes
math/rand + letters stringSimple random strings, tests, demosYesNoEasiest option
crypto/rand + letters stringTokens, passwords, sensitive valuesNoYesSlower but secure
Random bytes encoded as hex/base64Binary-safe IDsYes/MediumCan beUsually includes digits or symbols

math/rand vs crypto/rand

Featuremath/randcrypto/rand
PurposeSimulation, games, non-secure randomnessSecurity-sensitive randomness
SpeedFasterSlower
PredictabilityCan be predictedDesigned to be unpredictable
Error handlingUsually no error on number generationFunctions often return errors

Fixed alphabet vs generated character ranges

MethodExampleProsCons
Fixed alphabet stringletters[rand.Intn(len(letters))]Clear and easy to controlManual character list
Character rangesrandom between a-z or A-ZCan be compactMore logic needed to combine uppercase and lowercase cleanly

For beginners, a fixed alphabet string is usually the simplest and most readable choice.

Take Quiz

Cheat Sheet

const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

Simple function

func randomString(n int) string {
	if n <= 0 {
		return ""
	}

	b := make([]byte, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

Seed once

rand.Seed(time.Now().UnixNano())

Secure version

  • Use crypto/rand
  • Return (string, error)
  • Use it for tokens, secrets, and passwords

Rules to remember

  • Use a fixed alphabet when you want only certain characters.
  • Use math/rand for non-sensitive randomness.
  • Use crypto/rand for security-sensitive randomness.
  • Seed math/rand once, not on every function call.
  • Check n <= 0 to avoid invalid lengths.
  • Bytes are fine for ASCII letters like A-Z and a-z.

FAQ

How do I generate a random string with letters only in Go?

Create a string containing all allowed letters, then repeatedly pick random indexes from it and build a result string.

Is math/rand good enough for random strings in Go?

Yes for testing, demos, and non-sensitive values. No for passwords, tokens, or anything security-related.

How do I include both uppercase and lowercase letters?

Use an alphabet like:

const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

Why should I seed math/rand only once?

Seeding initializes the pseudo-random generator. Doing it once is cleaner and avoids unnecessary repeated setup.

Should I use bytes or runes for this?

Use bytes if your alphabet is only ASCII letters. Use runes if you need Unicode characters.

What happens if the requested length is 0?

A good helper function should return an empty string.

How can I make the function reusable for other character sets?

Pass the character set as a parameter, such as randomFromCharset(n, charset).

Take Quiz

Mini Project

Description

Build a small Go utility that generates random invitation codes made of uppercase and lowercase letters only. This demonstrates how to define an allowed character set, pick random characters, validate input, and reuse the logic in a practical program.

Goal

Create a Go program that generates one or more fixed-length random letter-only codes from the command line.

Requirements

  • Create a function that generates a random string of a given length using only A-Z and a-z.
  • Return an empty string if the requested length is 0 or negative.
  • Seed the random generator once before generating codes.
  • Print at least three random codes of the same length.
  • Keep the implementation limited to non-secure randomness using math/rand.
Take Quiz

Keep learning

Related questions

View more