Nano ID
![](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.
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:
Default Nano ID: -D5f3Z_0x1Gk9Qa
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:
Default Nano ID: 1A3F5B7C9D
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.
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)
}
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 3764088 319.3 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDAllocationsConcurrent-24 1295656 920.4 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen2/IDLen8-24 10669104 107.2 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen2/IDLen16-24 4377984 272.5 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen2/IDLen21-24 4176481 284.0 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen2/IDLen32-24 3911018 298.5 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen2/IDLen64-24 3376358 360.0 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen2/IDLen128-24 2724709 425.2 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen16/IDLen8-24 10926075 109.3 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen16/IDLen16-24 4351170 285.3 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen16/IDLen21-24 4241280 285.1 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen16/IDLen32-24 3880702 301.6 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen16/IDLen64-24 3450793 346.5 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen16/IDLen128-24 2765485 432.8 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen32/IDLen8-24 10972581 108.5 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen32/IDLen16-24 4389151 270.2 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen32/IDLen21-24 4308759 277.9 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen32/IDLen32-24 4101363 302.6 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen32/IDLen64-24 3494762 343.1 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen32/IDLen128-24 2759592 428.5 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen64/IDLen8-24 10629952 109.4 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen64/IDLen16-24 4338962 272.3 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen64/IDLen21-24 4259820 277.9 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen64/IDLen32-24 4094395 293.7 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen64/IDLen64-24 3517770 342.7 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen64/IDLen128-24 2822192 438.1 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen95/IDLen8-24 4836936 245.5 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen95/IDLen16-24 2506089 460.9 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen95/IDLen21-24 2318176 504.5 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen95/IDLen32-24 1998264 592.3 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen95/IDLen64-24 1383175 863.3 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGeneration/ASCII_AlphabetLen95/IDLen128-24 1000000 1183 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen2/IDLen8-24 8520642 146.4 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen2/IDLen16-24 3449158 339.2 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen2/IDLen21-24 3283437 380.6 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen2/IDLen32-24 2698916 465.0 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen2/IDLen64-24 1834533 653.1 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen2/IDLen128-24 1216830 988.2 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen16/IDLen8-24 8355386 142.2 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen16/IDLen16-24 3471207 354.4 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen16/IDLen21-24 3227361 368.6 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen16/IDLen32-24 2640146 452.3 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen16/IDLen64-24 1879162 660.1 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen16/IDLen128-24 1000000 1014 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen32/IDLen8-24 8326064 140.0 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen32/IDLen16-24 3549640 336.1 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen32/IDLen21-24 3240813 379.8 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen32/IDLen32-24 2648866 466.5 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen32/IDLen64-24 1914925 629.7 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen32/IDLen128-24 1239902 959.9 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen64/IDLen8-24 8487975 139.9 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen64/IDLen16-24 3571329 332.2 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen64/IDLen21-24 3321560 369.6 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen64/IDLen32-24 2642209 442.4 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen64/IDLen64-24 1939760 618.6 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen64/IDLen128-24 1248356 966.6 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen95/IDLen8-24 4564356 263.4 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen95/IDLen16-24 2334805 511.6 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen95/IDLen21-24 2114260 564.5 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen95/IDLen32-24 1693544 708.6 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen95/IDLen64-24 1000000 1120 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDGeneration/Unicode_AlphabetLen95/IDLen128-24 691281 1653 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen2/IDLen8-24 3593084 334.4 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen2/IDLen16-24 1617313 744.4 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen2/IDLen21-24 1575547 758.3 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen2/IDLen32-24 1543257 777.6 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen2/IDLen64-24 1372218 868.4 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen2/IDLen128-24 1000000 1003 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen16/IDLen8-24 3578565 341.0 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen16/IDLen16-24 1634140 775.2 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen16/IDLen21-24 1544725 762.2 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen16/IDLen32-24 1521037 782.4 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen16/IDLen64-24 1375514 867.9 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen16/IDLen128-24 1000000 1007 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen32/IDLen8-24 3513444 335.4 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen32/IDLen16-24 1624455 746.5 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen32/IDLen21-24 1601432 756.3 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen32/IDLen32-24 1540446 773.9 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen32/IDLen64-24 1342212 873.4 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen32/IDLen128-24 1205612 995.3 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen64/IDLen8-24 3547953 333.4 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen64/IDLen16-24 1658762 730.8 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen64/IDLen21-24 1623319 749.5 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen64/IDLen32-24 1545364 777.7 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen64/IDLen64-24 1375556 875.0 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen64/IDLen128-24 1209762 1016 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen95/IDLen8-24 1647453 720.9 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen95/IDLen16-24 875874 1404 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen95/IDLen21-24 815330 1453 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen95/IDLen32-24 720522 1646 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen95/IDLen64-24 540523 2364 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/ASCII_AlphabetLen95/IDLen128-24 407793 2991 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen2/IDLen8-24 2955350 406.8 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen2/IDLen16-24 1400955 851.4 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen2/IDLen21-24 1340168 889.4 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen2/IDLen32-24 1201118 988.7 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen2/IDLen64-24 1000000 1096 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen2/IDLen128-24 928040 1290 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen16/IDLen8-24 2940718 404.2 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen16/IDLen16-24 1409098 850.5 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen16/IDLen21-24 1337359 893.2 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen16/IDLen32-24 1221687 982.5 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 901033 1301 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen32/IDLen8-24 2997499 403.0 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen32/IDLen16-24 1409848 853.8 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen32/IDLen21-24 1342257 889.4 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen32/IDLen32-24 1212100 987.2 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen32/IDLen64-24 1000000 1094 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen32/IDLen128-24 933954 1285 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen64/IDLen8-24 2990991 406.4 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen64/IDLen16-24 1416535 850.1 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen64/IDLen21-24 1347488 899.1 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen64/IDLen32-24 1218874 981.8 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen64/IDLen64-24 1000000 1090 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen64/IDLen128-24 971662 1284 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen95/IDLen8-24 1497752 799.3 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen95/IDLen16-24 805038 1489 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen95/IDLen21-24 772276 1611 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen95/IDLen32-24 630078 1947 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen95/IDLen64-24 414772 2845 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDGenerationParallel/Unicode_AlphabetLen95/IDLen128-24 327726 3649 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen2/IDLen8-24 10956201 107.7 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen2/IDLen16-24 4351782 275.0 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen2/IDLen21-24 4233300 279.8 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen2/IDLen32-24 4052265 293.7 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen2/IDLen64-24 3525630 341.3 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen2/IDLen128-24 2804791 435.2 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen16/IDLen8-24 11000280 111.0 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen16/IDLen16-24 4328498 279.1 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen16/IDLen21-24 4013366 305.8 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen16/IDLen32-24 3757680 307.9 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen16/IDLen64-24 3486427 352.5 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen16/IDLen128-24 2757661 447.0 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen32/IDLen8-24 10448277 108.4 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen32/IDLen16-24 4373778 273.0 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen32/IDLen21-24 4198897 278.4 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen32/IDLen32-24 4021123 295.2 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen32/IDLen64-24 3461632 351.8 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen32/IDLen128-24 2806958 445.9 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen64/IDLen8-24 10478149 112.2 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen64/IDLen16-24 4309562 278.6 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen64/IDLen21-24 4222953 288.7 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen64/IDLen32-24 3954624 296.5 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen64/IDLen64-24 3473697 347.9 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen64/IDLen128-24 2787202 434.5 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen95/IDLen8-24 4969417 244.3 ns/op 8 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen95/IDLen16-24 2588766 457.2 ns/op 16 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen95/IDLen21-24 2430073 490.2 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen95/IDLen32-24 2091253 572.4 ns/op 32 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen95/IDLen64-24 1393569 855.1 ns/op 64 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/ASCII_AlphabetLen95/IDLen128-24 1000000 1152 ns/op 128 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen2/IDLen8-24 8278442 143.0 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen2/IDLen16-24 3365029 350.9 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen2/IDLen21-24 3244406 368.0 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen2/IDLen32-24 2652244 446.0 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen2/IDLen64-24 1956176 613.0 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen2/IDLen128-24 1200711 993.4 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen16/IDLen8-24 8488153 138.9 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen16/IDLen16-24 3472114 344.3 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen16/IDLen21-24 3283492 362.5 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen16/IDLen32-24 2703904 451.5 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen16/IDLen64-24 1837723 638.7 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen16/IDLen128-24 1228981 988.0 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen32/IDLen8-24 8349602 143.9 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen32/IDLen16-24 3443064 346.3 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen32/IDLen21-24 3259161 366.1 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen32/IDLen32-24 2680155 441.8 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen32/IDLen64-24 1931581 614.6 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen32/IDLen128-24 1233782 970.0 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen64/IDLen8-24 8430091 139.8 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen64/IDLen16-24 3553509 332.4 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen64/IDLen21-24 3321061 360.4 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen64/IDLen32-24 2722161 440.3 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen64/IDLen64-24 1933794 616.2 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen64/IDLen128-24 1216303 970.1 ns/op 288 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen95/IDLen8-24 4415660 263.0 ns/op 24 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen95/IDLen16-24 2353754 513.7 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen95/IDLen21-24 2073289 584.3 ns/op 48 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen95/IDLen32-24 1667299 705.9 ns/op 80 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen95/IDLen64-24 1000000 1154 ns/op 144 B/op 1 allocs/op
BenchmarkNanoIDWithVaryingAlphabetLengths/Unicode_AlphabetLen95/IDLen128-24 682177 1684 ns/op 288 B/op 1 allocs/op
PASS
ok github.com/sixafter/nanoid 286.615s
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.