nanoid ![Nano ID logo by Anton Lovchikov](https://ai.github.io/nanoid/logo.svg)
![](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)
A simple, fast, and efficient Go implementation of Nano ID, a tiny, secure, URL-friendly, unique string ID generator.
Features
- Short & Unique IDs: Generates compact and collision-resistant identifiers.
- Cryptographically Secure: Utilizes Go's
crypto/rand
package for generating cryptographically secure random numbers. This guarantees that the generated IDs are both unpredictable and suitable for security-sensitive applications.
- Customizable:
- Define your own set of characters for ID generation with a minimum length of 2 characters and maximum length of 256 characters.
- Define your own random number generator.
- Unicode and ASCII alphabets supported.
- Concurrency Safe: Designed to be safe for use in concurrent environments.
- High Performance: Optimized with buffer pooling to minimize allocations and enhance speed.
- Optimized for Low Allocations: Carefully structured to minimize heap allocations, reducing memory overhead and improving cache locality. This optimization is crucial for applications where performance and resource usage are critical.
- 1
allocs/op
for ASCII and Unicode alphabets.
- Zero Dependencies: Lightweight implementation with no external dependencies beyond the standard library.
- Supports
io.Reader
Interface:
- The Nano ID generator now satisfies the
io.Reader
interface, allowing it to be used interchangeably with any io.Reader
implementations.
- Developers can now utilize the Nano ID generator in contexts such as streaming data processing, pipelines, and other I/O-driven operations.
Installation
To install the package, use:
go get -u github.com/sixafter/nanoid
Importing the Package
To use the NanoID package in your Go project, import it as follows:
import "github.com/sixafter/nanoid"
Usage
Basic Usage with Default Settings
The simplest way to generate a Nano ID is by using the default settings. This utilizes the predefined alphabet and default ID length.
package main
import (
"fmt"
"github.com/sixafter/nanoid"
)
func main() {
id, err := nanoid.New()
if err != nil {
panic(err)
}
fmt.Println("Generated ID:", id)
}
Output:
Generated ID: mGbzQkkPBidjL4IP_MwBM
Generating a Nano ID with Custom length
Generate a NanoID with a custom length.
package main
import (
"fmt"
"github.com/sixafter/nanoid"
)
func main() {
id, err := nanoid.NewWithLength(10)
if err != nil {
panic(err)
}
fmt.Println("Generated ID:", id)
}
Output:
Generated ID: 1A3F5B7C9D
Using io.Reader
Interface
Here's a simple example demonstrating how to use the Nano ID generator as an io.Reader
:
package main
import (
"fmt"
"io"
"github.com/sixafter/nanoid"
)
func main() {
// Nano ID default length is 21
buf := make([]byte, nanoid.DefaultLength)
// Read a Nano ID into the buffer
_, err := nanoid.Read(buf)
if err != nil && err != io.EOF {
panic(err)
}
// Convert the byte slice to a string
id := string(buf)
fmt.Printf("Generated ID: %s\n", id)
}
Output:
Generated ID: 2mhTvy21bBZhZcd80ZydM
Customizing the Alphabet and ID Length
You can customize the alphabet by using the WithAlphabet option and generate an ID with a custom length.
package main
import (
"fmt"
"github.com/sixafter/nanoid"
)
func main() {
// Define a custom alphabet
alphabet := "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
// Create a new generator with custom alphabet and length hint
gen, err := nanoid.NewGenerator(
nanoid.WithAlphabet(alphabet),
nanoid.WithLengthHint(10),
)
if err != nil {
fmt.Println("Error creating Nano ID generator:", err)
return
}
// Generate a Nano ID using the custom generator
id, err := gen.New(10)
if err != nil {
fmt.Println("Error generating Nano ID:", err)
return
}
fmt.Println("Custom Nano ID:", id)
}
Output"
Custom Nano ID: G5J8K2M0QZ
Functions
New
Generates a Nano ID with the specified length using the default generator.
func New() (string, error)
- Returns:
string
: The generated Nano ID.
error
: An error if the generation fails.
NewWithLength
Generates a Nano ID with the specified length using the default generator.
func NewWithLength(length int) (string, error)
- Parameters:
length
(int
): The desired length of the Nano ID. Must be a positive integer.
- Returns:
string
: The generated Nano ID.
error
: An error if the generation fails.
Must
Generates a Nano ID with the specified length using the default generator.
func Must() string
- Returns:
string
: The generated Nano ID.
MustWithLength
Generates a Nano ID with the specified length using the default generator.
func NewWithLength(length int) string
- Parameters:
length
(int
): The desired length of the Nano ID. Must be a positive integer.
- Returns:
string
: The generated Nano ID.
NewGenerator
Creates a new Nano ID generator with a custom alphabet and random source.
func NewGenerator(options ...Option) (Generator, error)
- Parameters:
options
(Option
): Variadic Option parameters to configure the Generator
. Options are:
WithAlphabet
: Sets a custom alphabet for the Generator
, allowing the user to specify which characters will be used in the generated IDs.
WithRandReader
: Sets a custom random reader for the Generator
, enabling the use of a specific source of randomness.
WithLengthHint
: Sets a hint for the intended length of the generated IDs, helping to optimize internal allocations based on the expected ID size.
- Returns:
Generator
: A new Nano ID generator.
error
: An error if the configuration is invalid.
Read
Generates a Nano ID with the specified length using the default generator.
func Read(p []byte) (n int, err error)
- Parameters:
p
([]byte
): The byte slice to store the generated ID.
- Returns:
n
: The actual number of bytes read.
error
: An error if the generation fails.
Generator
Interface
Defines the method to generate Nano IDs.
// Generator defines the interface for generating Nano IDs.
type Generator interface {
// New returns a new Nano ID of the specified length.
New(length int) (string, error)
// Read reads up to len(p) bytes into p. It returns the number of bytes read.
Read(p []byte) (n int, err error)
}
Configuration
Interface
Provides access to the generator's configuration.
// Configuration defines the interface for retrieving generator configuration.
type Configuration interface {
// Config returns the configuration of the generator.
Config() Config
}
Error Handling
The nanoid module defines several error types to handle various failure scenarios:
ErrDuplicateCharacters
: Returned when the alphabet contains duplicate characters.
ErrExceededMaxAttempts
: Returned when the generation process exceeds the maximum number of attempts.
ErrInvalidLength
: Returned when a non-positive Nano ID length is specified.
ErrInvalidAlphabet
: Returned when an alphabet is invalid; e.g. due to length constraints.
ErrNonUTF8Alphabet
: Returned when an alphabet contains invalid UTF-8 characters.
ErrAlphabetTooShort
: Returned when alphabet length is less than 2 characters.
ErrAlphabetTooLong
: Returned when an alphabet length exceeds 256 characters.
ErrNilRandReader
: Returned when a nil random reader is provided.
Constants
DefaultAlphabet
: The default alphabet used for ID generation: _-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
DefaultLength
: The default length of the generated ID: 21
MinAlphabetLength
: The minimum allowed length for the alphabet: 2
MaxAlphabetLength
: The maximum allowed length for the alphabet: 256
Buffer Pooling with sync.Pool
The nanoid generator utilizes sync.Pool
to manage byte slice buffers efficiently. This approach minimizes memory allocations and enhances performance, especially in high-concurrency scenarios.
How It Works:
- Storing Pointers:
sync.Pool
stores pointers to []byte
slices (*[]byte
) instead of the slices themselves. This avoids unnecessary allocations and aligns with best practices for using sync.Pool
.
- Zeroing Buffers: Before returning buffers to the pool, they are zeroed out to prevent data leaks.
Struct Optimization
The generator
struct is optimized for memory alignment and size by ordering from largest to smallest to minimize padding and optimize memory usage.
Execute Benchmarks:
Run the benchmarks using the go test
command with the bench
make target:
make bench
Interpreting Results:
Sample output might look like this:
Expand to see results
go clean
go test -bench=. -benchmem -memprofile=mem.out -cpuprofile=cpu.out
goos: darwin
goarch: arm64
pkg: github.com/sixafter/nanoid
cpu: Apple M2 Ultra
BenchmarkNanoIDAllocations-24 3712894 322.7 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDAllocationsConcurrent-24 1231219 955.8 ns/op 24 B/op 1 allocs/op
BenchmarkGenerator_Read_DefaultLength-24 4234353 280.7 ns/op 24 B/op 1 allocs/op
BenchmarkGenerator_Read_VaryingBufferSizes/BufferSize_2-24 12416870 93.76 ns/op 2 B/op 1 allocs/op
BenchmarkGenerator_Read_VaryingBufferSizes/BufferSize_3-24 12173713 99.60 ns/op 3 B/op 1 allocs/op
BenchmarkGenerator_Read_VaryingBufferSizes/BufferSize_5-24 10923501 107.6 ns/op 5 B/op 1 allocs/op
BenchmarkGenerator_Read_VaryingBufferSizes/BufferSize_13-24 4239207 270.7 ns/op 16 B/op 1 allocs/op
BenchmarkGenerator_Read_VaryingBufferSizes/BufferSize_21-24 4208509 281.1 ns/op 24 B/op 1 allocs/op
BenchmarkGenerator_Read_VaryingBufferSizes/BufferSize_34-24 3979149 305.3 ns/op 48 B/op 1 allocs/op
BenchmarkGenerator_Read_ZeroLengthBuffer-24 639281161 1.849 ns/op 0 B/op 0 allocs/op
BenchmarkGenerator_Read_Concurrent/Concurrency_1-24 4263008 277.4 ns/op 24 B/op 1 allocs/op
BenchmarkGenerator_Read_Concurrent/Concurrency_2-24 2359436 504.1 ns/op 24 B/op 1 allocs/op
BenchmarkGenerator_Read_Concurrent/Concurrency_4-24 2109841 579.5 ns/op 24 B/op 1 allocs/op
BenchmarkGenerator_Read_Concurrent/Concurrency_8-24 1752210 691.3 ns/op 24 B/op 1 allocs/op
BenchmarkGenerator_Read_Concurrent/Concurrency_16-24 1559118 771.3 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen2/IDLen8-24 10983956 107.2 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen2/IDLen16-24 4418779 271.6 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen2/IDLen21-24 4360071 276.5 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen2/IDLen32-24 4148890 290.3 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen2/IDLen64-24 3441111 341.5 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen2/IDLen128-24 2868350 418.5 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen16/IDLen8-24 10985125 107.3 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen16/IDLen16-24 4445092 272.2 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen16/IDLen21-24 4210738 280.6 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen16/IDLen32-24 4063539 293.6 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen16/IDLen64-24 3444986 343.7 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen16/IDLen128-24 2843654 418.3 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen32/IDLen8-24 11157402 106.2 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen32/IDLen16-24 4483576 267.6 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen32/IDLen21-24 4215984 279.6 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen32/IDLen32-24 4068142 289.4 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen32/IDLen64-24 3521085 339.6 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen32/IDLen128-24 2830250 418.3 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen64/IDLen8-24 11252030 105.6 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen64/IDLen16-24 4366692 270.8 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen64/IDLen21-24 4237465 277.9 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen64/IDLen32-24 4135947 291.2 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen64/IDLen64-24 3521300 342.6 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen64/IDLen128-24 2839201 416.9 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen2/IDLen8-24 8620464 138.4 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen2/IDLen16-24 3589316 335.3 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen2/IDLen21-24 3283752 362.6 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen2/IDLen32-24 2684456 442.9 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen2/IDLen64-24 1934439 624.9 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen2/IDLen128-24 1239282 952.9 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen16/IDLen8-24 8569690 138.7 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen16/IDLen16-24 3584649 334.2 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen16/IDLen21-24 3297488 362.6 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen16/IDLen32-24 2699508 442.9 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen16/IDLen64-24 1943648 624.9 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen16/IDLen128-24 1254345 968.4 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen32/IDLen8-24 8263024 139.8 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen32/IDLen16-24 3584301 333.1 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen32/IDLen21-24 3330494 368.5 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen32/IDLen32-24 2673807 457.9 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen32/IDLen64-24 1926444 627.1 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen32/IDLen128-24 1234162 970.5 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen64/IDLen8-24 8431142 140.7 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen64/IDLen16-24 3542473 335.7 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen64/IDLen21-24 3319472 365.9 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen64/IDLen32-24 2671075 449.5 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen64/IDLen64-24 1907966 627.3 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen64/IDLen128-24 1222561 1001 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen2/IDLen8-24 2961512 379.5 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen2/IDLen16-24 1529432 786.1 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen2/IDLen21-24 1517160 789.1 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen2/IDLen32-24 1472512 809.6 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen2/IDLen64-24 1341105 899.1 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen2/IDLen128-24 1000000 1007 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen16/IDLen8-24 3250173 369.9 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen16/IDLen16-24 1548758 777.2 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen16/IDLen21-24 1531372 785.8 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen16/IDLen32-24 1484287 818.3 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen16/IDLen64-24 1349370 897.7 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen16/IDLen128-24 1000000 1005 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen32/IDLen8-24 3223686 367.9 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen32/IDLen16-24 1559476 763.6 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen32/IDLen21-24 1538126 786.9 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen32/IDLen32-24 1489722 808.4 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen32/IDLen64-24 1334155 893.8 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen32/IDLen128-24 1000000 1007 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen64/IDLen8-24 3228020 367.0 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen64/IDLen16-24 1562257 772.9 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen64/IDLen21-24 1534208 794.1 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen64/IDLen32-24 1482178 820.8 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen64/IDLen64-24 1291593 912.6 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen64/IDLen128-24 1000000 1013 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen2/IDLen8-24 2582572 447.4 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen2/IDLen16-24 1356303 884.3 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen2/IDLen21-24 1297418 916.1 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen2/IDLen32-24 1205206 999.9 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen2/IDLen64-24 1000000 1105 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen2/IDLen128-24 954236 1289 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen16/IDLen8-24 2734597 439.7 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen16/IDLen16-24 1370898 870.0 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen16/IDLen21-24 1308649 911.4 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen16/IDLen32-24 1207134 1001 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen16/IDLen64-24 1000000 1096 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen16/IDLen128-24 909823 1284 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen32/IDLen8-24 2727334 447.3 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen32/IDLen16-24 1367902 874.9 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen32/IDLen21-24 1304487 909.8 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen32/IDLen32-24 1210693 992.3 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen32/IDLen64-24 1000000 1100 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen32/IDLen128-24 936051 1282 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen64/IDLen8-24 2763672 440.0 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen64/IDLen16-24 1374480 877.7 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen64/IDLen21-24 1311806 915.6 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen64/IDLen32-24 1206374 998.4 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen64/IDLen64-24 1000000 1110 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen64/IDLen128-24 905634 1293 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen2/IDLen8-24 10815402 111.7 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen2/IDLen16-24 4383463 274.0 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen2/IDLen21-24 4291173 281.6 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen2/IDLen32-24 4070809 293.2 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen2/IDLen64-24 3513301 345.1 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen2/IDLen128-24 2846863 420.5 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen16/IDLen8-24 10877348 106.7 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen16/IDLen16-24 4422064 271.9 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen16/IDLen21-24 4270226 280.4 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen16/IDLen32-24 4150038 290.4 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen16/IDLen64-24 3549493 338.5 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen16/IDLen128-24 2864341 423.0 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen32/IDLen8-24 11224105 107.7 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen32/IDLen16-24 4445605 271.7 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen32/IDLen21-24 4286137 279.6 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen32/IDLen32-24 4077279 293.0 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen32/IDLen64-24 3550720 338.2 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen32/IDLen128-24 2860690 417.7 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen64/IDLen8-24 11053956 106.8 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen64/IDLen16-24 4430721 269.8 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen64/IDLen21-24 4274026 281.6 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen64/IDLen32-24 4103462 294.2 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen64/IDLen64-24 3465758 341.4 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen64/IDLen128-24 2826387 423.0 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen2/IDLen8-24 8437821 140.1 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen2/IDLen16-24 3514735 333.5 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen2/IDLen21-24 3296300 359.7 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen2/IDLen32-24 2735949 438.0 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen2/IDLen64-24 1939842 617.0 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen2/IDLen128-24 1252837 964.5 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen16/IDLen8-24 8389263 140.8 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen16/IDLen16-24 3565263 334.2 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen16/IDLen21-24 3299416 359.6 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen16/IDLen32-24 2689170 438.2 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen16/IDLen64-24 1944435 616.8 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen16/IDLen128-24 1243393 957.3 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen32/IDLen8-24 8506532 140.3 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen32/IDLen16-24 3623780 335.9 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen32/IDLen21-24 3332631 360.4 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen32/IDLen32-24 2690766 439.7 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen32/IDLen64-24 1938931 611.8 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen32/IDLen128-24 1259449 954.4 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen64/IDLen8-24 8482705 138.6 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen64/IDLen16-24 3617001 332.1 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen64/IDLen21-24 3348201 359.2 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen64/IDLen32-24 2670768 440.9 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen64/IDLen64-24 1944044 611.5 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen64/IDLen128-24 1245513 951.2 ns/op 288 B/op 1 allocs/op
PASS
ok github.com/sixafter/nanoid 260.726s
ns/op
: Nanoseconds per operation. Lower values indicate faster performance.
B/op
: Bytes allocated per operation. Lower values indicate more memory-efficient code.
allocs/op
: Number of memory allocations per operation. Fewer allocations generally lead to better performance.
Nano ID Generation
Nano ID generates unique identifiers based on the following:
- Random Byte Generation: Nano ID generates a sequence of random bytes using a secure random source (e.g.,
crypto/rand.Reader
).
- Mapping to Alphabet: Each random byte is mapped to a character in a predefined alphabet to form the final ID.
- Uniform Distribution: To ensure that each character in the alphabet has an equal probability of being selected, Nano ID employs techniques to avoid bias, especially when the alphabet size isn't a power of two.
Custom Alphabet Constraints
- Alphabet Lengths:
- At Least Two Characters: The custom alphabet must contain at least two unique characters. An alphabet with fewer than two characters cannot produce IDs with sufficient variability or randomness.
- Maximum Length 256 Characters: The implementation utilizes a rune-based approach, where each character in the alphabet is represented by a single rune. This allows for a broad range of unique characters, accommodating alphabets with up to 256 distinct runes. Attempting to use an alphabet with more than 256 runes will result in an error.
- Uniqueness of Characters:
- All Characters Must Be Unique. Duplicate characters in the alphabet can introduce biases in ID generation and compromise the randomness and uniqueness of the IDs. The generator enforces uniqueness by checking for duplicates during initialization. If duplicates are detected, it will return an
ErrDuplicateCharacters
error.
- Character Encoding:
- Support for Unicode: The generator accepts alphabets containing Unicode characters, allowing you to include a wide range of symbols, emojis, or characters from various languages.
- Power-of-Two Considerations:
- Mask Calculation: The generator calculates a mask based on the number of bits required to represent the alphabet length minus one.
k := bits.Len(uint(alphabetLen - 1))
mask := byte((1 << k) - 1)
- Implications: While the alphabet length doesn't need to be a power of two, the mask is used to efficiently reduce bias in random number generation. The implementation ensures that each character in the alphabet has an equal probability of being selected by using this mask.
Determining Collisions
To determine the practical length for a NanoID for your use cases, see the collision time calculator here.
Contributing
Contributions are welcome. See CONTRIBUTING
License
This project is licensed under the Apache 2.0 License. See LICENSE file.