A high-performance, thread-safe Snowflake ID generator implementation in Go. Snowflake IDs are unique 64-bit integers that are sortable by time, making them ideal for distributed systems.
- Thread-safe: Safely generate IDs from multiple goroutines
- High performance: Capable of generating millions of IDs per second
- Customizable: Configure worker ID, datacenter ID, and custom epoch
- Time-sortable: IDs are roughly sortable by creation time
- No dependencies: Uses only Go standard library
go get github.com/axoneo/snowflake-id-gopackage main
import (
"fmt"
"log"
"github.com/axoneo/snowflake-id-go"
)
func main() {
// Create a new generator
gen, err := snowflake.NewGenerator(snowflake.Config{
WorkerID: 1,
DatacenterID: 1,
})
if err != nil {
log.Fatal(err)
}
// Generate IDs
id, err := gen.NextID()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Generated ID: %d\n", id)
}A Snowflake ID is a 64-bit integer composed of:
| 1 bit (unused) | 41 bits (timestamp) | 5 bits (datacenter) | 5 bits (worker) | 12 bits (sequence) |
- 1 bit: Unused (always 0)
- 41 bits: Milliseconds since custom epoch (default: January 1, 2024)
- 5 bits: Datacenter ID (0-31)
- 5 bits: Worker ID (0-31)
- 12 bits: Sequence number (0-4095)
This allows for:
- 32 datacenters
- 32 workers per datacenter
- 4096 IDs per millisecond per worker
- ~69 years of IDs (from the epoch)
gen, err := snowflake.NewGenerator(snowflake.Config{
WorkerID: 1,
DatacenterID: 1,
})
if err != nil {
log.Fatal(err)
}
id, err := gen.NextID()
if err != nil {
log.Fatal(err)
}
fmt.Println(id) // Output: 123456789012345678// Use a custom epoch (January 1, 2020)
gen, err := snowflake.NewGenerator(snowflake.Config{
WorkerID: 1,
DatacenterID: 1,
Epoch: 1577836800000, // milliseconds
})id := int64(123456789012345678)
// Parse all components
timestamp, datacenterID, workerID, sequence := snowflake.ParseID(id)
fmt.Printf("Timestamp: %d, Datacenter: %d, Worker: %d, Sequence: %d\n",
timestamp, datacenterID, workerID, sequence)
// Get just the timestamp as time.Time
t := snowflake.GetTimestamp(id)
fmt.Printf("Created at: %s\n", t.Format(time.RFC3339))The generator is thread-safe and can be used from multiple goroutines:
gen, _ := snowflake.NewGenerator(snowflake.Config{
WorkerID: 1,
DatacenterID: 1,
})
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
id, _ := gen.NextID()
fmt.Println(id)
}()
}
wg.Wait()type Config struct {
Epoch int64 // Custom epoch in milliseconds (optional, uses default if 0)
WorkerID int64 // Worker ID (0-31)
DatacenterID int64 // Datacenter ID (0-31)
}- WorkerID: Must be between 0 and 31
- DatacenterID: Must be between 0 and 31
- Epoch: Custom epoch in milliseconds (optional)
The generator is highly optimized for performance. Real-world benchmark results with multiple goroutines sharing a single generator:
100 goroutines for 5 seconds: ~3.1 million IDs/second
50 goroutines for 3 seconds: ~3.3 million IDs/second
The generator can handle:
- 3+ million IDs per second with high concurrency
- Linear scalability across multiple goroutines
- Minimal contention even with 100+ concurrent workers
Run your own benchmarks:
cd benchmark
go run main.go -d 5s -g 100 # 100 goroutines for 5 secondsThe library returns errors in the following cases:
- ErrInvalidWorkerID: Worker ID is not between 0 and 31
- ErrInvalidDatacenterID: Datacenter ID is not between 0 and 31
- ErrInvalidEpoch: Epoch value is in future
Run the test suite:
go test -vA comprehensive benchmarking tool is included in the benchmark/ directory:
cd benchmark
go run main.go -d 5s -g 100 # 100 goroutines for 5 seconds
go run main.go -d 10s -g 200 # 200 goroutines for 10 seconds
go run main.go -g 50 # Default 5 seconds with 50 goroutinesFlags:
-d: Duration to run (e.g.,5s,10s,1m)-g: Number of goroutines (default: 100)
Snowflake IDs are perfect for:
- Distributed systems requiring unique IDs
- Database primary keys
- Event IDs in event sourcing
- Message IDs in message queues
- Order IDs in e-commerce systems
- Any scenario requiring sortable, unique identifiers
This is free and unencumbered software released into the public domain.
Contributions are welcome! Please feel free to submit a Pull Request.