A lightweight and fast TypeScript library for generating unique, sortable 64-bit IDs inspired by Twitter's Snowflake algorithm and Discord's ID system.
- ⚡ Zero Dependencies: Lightweight and fast
- 🔒 Sequence Safe: Handle rapid generation with sequence overflow protection
- ⚙️ Configurable: Customize bit allocations for your use case
- 🛡️ Graceful Error Handling: Handles clock drift and sequence overflow cases without throwing errors
- 🎯 TypeScript First: Full type safety with comprehensive interfaces
npm install @pokedotdev/snowflake
import { SnowflakeGenerator } from '@pokedotdev/snowflake';
// Create a generator with a unique worker ID
const generator = new SnowflakeGenerator({ workerId: 1 });
// Generate unique IDs
const id1 = generator.generate(); // 1234567890123456789n
const id2 = generator.generate(); // 1234567890123456790n
// IDs are naturally sortable by generation time
console.log(id1 < id2); // true
The library uses a flexible bit allocation system. By default:
- 1 bit: Unused (always 0)
- 41 bits: Timestamp (milliseconds since epoch)
- 10 bits: Worker ID (0-1023)
- 0 bits: Process ID
- 12 bits: Sequence (0-4095 per millisecond)
const generator = new SnowflakeGenerator({
workerId: 42, // Required: unique worker identifier
processId: 0, // Optional: process identifier (default: 0)
epoch: 1640995200000, // Optional: custom epoch (default: 2020-01-01)
});
Customize bit allocations for your specific needs using the bits
configuration object:
const generator = new SnowflakeGenerator({
workerId: 1,
bits: {
workerId: 8, // 256 possible workers (0-255)
processId: 4, // 16 possible processes (0-15)
sequence: 10, // 1024 IDs per millisecond (0-1023)
// Total: 8 + 4 + 10 = 22 bits (within 64-bit limit)
}
});
new SnowflakeGenerator(config: SnowflakeConfig)
Generate a new unique Snowflake ID.
const id = generator.generate();
console.log(id); // 1234567890123456789n
Create an ID from individual components.
const id = generator.compose(
Date.now(), // timestamp
1, // workerId
0, // processId
42 // sequence
);
Extract components from an existing ID.
const components = generator.decompose(1234567890123456789n);
console.log(components);
// {
// timestamp: 1640995200000,
// workerId: 1,
// processId: 0,
// sequence: 42
// }
interface SnowflakeConfig {
/** Custom epoch timestamp in milliseconds (default: 2020-01-01) */
epoch?: number;
/** Worker ID for this instance */
workerId: number;
/** Process ID for this instance (default: 0) */
processId?: number;
/** Bit allocation configuration (optional) */
bits?: BitAllocation;
}
interface BitAllocation {
/** Number of bits for worker ID (default: 10) */
workerId: number;
/** Number of bits for process ID (default: 0) */
processId: number;
/** Number of bits for sequence (default: 12) */
sequence: number;
}
interface SnowflakeComponents {
/** Timestamp in milliseconds since epoch */
timestamp: number;
/** Worker ID */
workerId: number;
/** Process ID */
processId: number;
/** Sequence number */
sequence: number;
}
The library provides specific error classes for different failure scenarios:
import {
SnowflakeGenerator,
ConfigurationError,
InvalidIdError
} from '@pokedotdev/snowflake';
try {
const generator = new SnowflakeGenerator({
workerId: 2000,
bits: { workerId: 10, processId: 0, sequence: 12 }
});
} catch (error) {
if (error instanceof ConfigurationError) {
console.error('Configuration error:', error.message);
// "Worker ID (2000) exceeds maximum value (1023) for 10 bits"
}
}
ConfigurationError
: Invalid configuration parametersInvalidIdError
: Invalid ID format during decomposition
// For small deployments (fewer workers, more throughput)
const generator = new SnowflakeGenerator({
workerId: 1,
bits: {
workerId: 8, // 256 workers max
processId: 0, // No process distinction
sequence: 14, // 65,536 IDs/ms
}
});
// For large deployments (more workers, adequate throughput)
const generator = new SnowflakeGenerator({
workerId: 1,
bits: {
workerId: 10, // 1,024 workers max
processId: 0, // No process distinction
sequence: 12, // 4,096 IDs/ms
}
});
// Use the same epoch across all services
const COMPANY_EPOCH = new Date('2024-01-01').getTime();
const generator = new SnowflakeGenerator({
workerId: 1,
epoch: COMPANY_EPOCH,
});
The library validates all configurations at construction time:
// ✅ Valid - total bits: 8 + 4 + 10 = 22
new SnowflakeGenerator({
workerId: 1,
bits: {
workerId: 8,
processId: 4,
sequence: 10,
}
});
// ❌ Invalid - total bits: 10 + 10 + 10 = 30 > 22
new SnowflakeGenerator({
workerId: 1,
bits: {
workerId: 10,
processId: 10,
sequence: 10,
}
}); // Throws ConfigurationError
For common use cases, you can use these predefined bit allocations:
// Default: Good balance for most applications
const defaultConfig = { workerId: 10, processId: 0, sequence: 12 };
// Distributed: For microservices with multiple processes
const distributedConfig = { workerId: 8, processId: 4, sequence: 10 };
// High-throughput: Maximum sequence capacity
const highThroughputConfig = { workerId: 6, processId: 0, sequence: 16 };
// Example usage
const generator = new SnowflakeGenerator({
workerId: 1,
bits: distributedConfig
});
Install dependencies:
pnpm install
Run tests:
pnpm run test
Build the library:
pnpm run build
Type checking:
pnpm run typecheck
Format code:
pnpm run format
Contributions are welcome! Please feel free to submit a Pull Request.