Julien's dev blog

Gist: Human-friendly IDs in Go

Generate crypto/rand IDs in Go and encode to a safe charset.

Last updated on: 2025-05-25

Goals:

  • Use a charset made of non-graphically confusable characters
  • Use base-16 text encoding
  • Be human-friendly

Default charset (16 characters): "2346789CHJKPTVXY".

package huid

import (
	"crypto/rand"
	"fmt"
	"io"
)

// Generates a human-friendly ID using that only contains "safe" non-confusable characters
// and no vowels (to avoid generating human words).
// The character set is made from 16 alpha-numeric visually distinct ASCII characters.
func New(nBytes int) (id string) {
	b := make([]byte, nBytes)
	_, err := io.ReadFull(rand.Reader, b)
	if err != nil {
		panic(fmt.Errorf("read %d bytes from PRNG: %w", nBytes, err))
	}

	// Encode with safe charset.
	const charset = "2346789CHJKPTVXY"
	if len(charset) != 16 {
		panic("bad HuID charset")
	}
	for _, v := range b {
		id += string(charset[(v&0b11110000)>>4])
		id += string(charset[(v&0b00001111)>>0])
	}

	return id
}

NB: Since base-16 encoding is used, one BYTE (not bits) of entropy results in two output BYTES in the `New` function below.