Simpleflakes
Fast and test-driven distributed 64-bit ID generation, using pure JavaScript, for Node.js.
Install / Use
/learn @leodutra/SimpleflakesREADME
simpleflakes
[![npm][npm-badge]][npm-link]
[![coveralls status][coveralls-badge]][coveralls-link]
Fast, lightweight, and reliable distributed 64-bit ID generation for Node.js Zero dependencies • TypeScript-ready • 8.8M+ ops/sec performance
Features
- ⚡ 8.8M+ ops/sec - Ultra-fast performance
- 🔢 Time-oriented 64-bit IDs - Globally unique, sortable by creation time
- 0️⃣ Zero dependencies - Pure JavaScript, lightweight bundle
- 🏷️ TypeScript-ready - Full type safety and universal module support
- 🚀 Production-ready - 100% test coverage, Snowflake compatible
Table of Contents
- What is Simpleflake?
- Installation
- Quick Start
- Advanced Usage
- ID Structure
- Performance
- Architecture
- Use Cases
- API Reference
- Migration Guide
- Comparison
- Contributing
What is Simpleflake?
Simpleflake generates unique 64-bit integers that are:
- Time-ordered - IDs generated later are numerically larger
- Distributed-safe - No coordination needed between multiple generators
- Compact - Fits in a 64-bit integer (vs UUID's 128 bits)
- URL-friendly - Can be represented as short strings
Perfect for database primary keys, distributed system IDs, and anywhere you need fast, unique identifiers.
References
- Original Presentation - Introduction to the concept by Mali Akmanalp
- Video Discussion - Detailed explanation and use cases
- Python Implementation - Original reference implementation
- Twitter Snowflake - Similar distributed ID system
Installation
npm install simpleflakes
Quick Start
JavaScript (CommonJS)
const { simpleflake } = require('simpleflakes');
// Generate a unique ID
const id = simpleflake();
console.log(id); // 4234673179811182512n (BigInt)
// Convert to different formats
console.log(id.toString()); // "4234673179811182512"
console.log(id.toString(16)); // "3ac494d21e84f7b0" (hex)
console.log(id.toString(36)); // "w68acyhy50hc" (base36 - shortest)
TypeScript / ES Modules
import { simpleflake, parseSimpleflake, type SimpleflakeStruct } from 'simpleflakes';
// Generate with full type safety
const id: bigint = simpleflake();
// Parse the ID to extract timestamp and random bits
const parsed: SimpleflakeStruct = parseSimpleflake(id);
console.log(parsed.timestamp); // "1693244847123" (Unix timestamp as string)
console.log(parsed.randomBits); // "4567234" (Random component as string)
Advanced Usage
Custom Parameters
// Generate with custom timestamp and random bits
const customId = simpleflake(
Date.now(), // timestamp (default: Date.now())
12345, // random bits (default: 23-bit random)
Date.UTC(2000, 0, 1) // epoch (default: Year 2000)
);
Working with Binary Data
import { binary, extractBits } from 'simpleflakes';
const id = simpleflake();
// View binary representation
console.log(binary(id));
// Output: "0011101011000100100100110100001000011110100001001111011110110000"
// Extract specific bit ranges
const timestampBits = extractBits(id, 23n, 41n); // Extract 41 bits starting at position 23
const randomBits = extractBits(id, 0n, 23n); // Extract first 23 bits
Batch Generation
// Generate multiple IDs efficiently
function generateBatch(count) {
const ids = [];
for (let i = 0; i < count; i++) {
ids.push(simpleflake());
}
return ids;
}
const batch = generateBatch(1000);
console.log(`Generated ${batch.length} unique IDs`);
ID Structure
Each 64-bit simpleflake ID contains:
|<------- 41 bits ------->|<- 23 bits ->| |-------------------------|-------------| |Timestamp |Random | |(milliseconds from epoch)|(0-8388607) |
- 41 bits timestamp: Milliseconds since epoch (Year 2000)
- 23 bits random: Random number for uniqueness within the same millisecond
- Total: 64 bits = fits in a signed 64-bit integer
This gives you:
- 69+ years of timestamp range (until year 2069)
- 8.3 million unique IDs per millisecond
- Extremely low collision chance - 1 in 8.3 million per millisecond
- Sortable by creation time when converted to integers
Performance
This library is optimized for speed:
// Benchmark results (operations per second)
simpleflake() // ~8.8M+ ops/sec
parseSimpleflake() // ~3.9M+ ops/sec
binary() // ~26M+ ops/sec
Perfect for high-throughput applications requiring millions of IDs per second.
Architecture
Why 64-bit IDs?
- Database-friendly: Most databases optimize for 64-bit integers
- Memory efficient: Half the size of UUIDs (128-bit)
- Performance: Integer operations are faster than string operations
- Sortable: Natural ordering by creation time
- Compact URLs: Shorter than UUIDs when base36-encoded
Distributed Generation
No coordination required between multiple ID generators:
- Clock skew tolerant: Small time differences between servers are fine
- Random collision protection: 23 random bits provide 8.3M combinations per millisecond
- High availability: Each service can generate IDs independently
Use Cases
Database Primary Keys
// Perfect for database IDs - time-ordered and unique
const userId = simpleflake();
await db.users.create({ id: userId.toString(), name: "John" });
Distributed System IDs
// Each service can generate IDs independently
const serviceAId = simpleflake(); // Service A
const serviceBId = simpleflake(); // Service B
// No coordination needed, guaranteed unique across services
Short URLs
// Generate compact URL identifiers
const shortId = simpleflake().toString(36); // "w68acyhy50hc"
const url = `https://short.ly/${shortId}`;
Event Tracking
// Time-ordered event IDs for chronological processing
const eventId = simpleflake();
await analytics.track({ eventId, userId, action: "click" });
API Reference
Core Functions
simpleflake(timestamp?, randomBits?, epoch?): bigint
Generates a unique 64-bit ID.
Parameters:
timestamp(number, optional): Unix timestamp in milliseconds. Default:Date.now()randomBits(number, optional): Random bits (0-8388607). Default: random 23-bit numberepoch(number, optional): Epoch start time. Default:Date.UTC(2000, 0, 1)
Returns: BigInt - The generated ID
const id = simpleflake();
const customId = simpleflake(Date.now(), 12345, Date.UTC(2000, 0, 1));
parseSimpleflake(flake): SimpleflakeStruct
Parses a simpleflake ID into its components.
Parameters:
flake(bigint | string | number): The ID to parse
Returns: Object with timestamp and randomBits properties (both bigint)
const parsed = parseSimpleflake(4234673179811182512n);
console.log(parsed.timestamp); // "1693244847123"
console.log(parsed.randomBits); // "4567234"
binary(value, padding?): string
Converts a number to binary string representation.
Parameters:
value(bigint | string | number): Value to convertpadding(boolean, optional): Whether to pad to 64 bits. Default:true
Returns: String - Binary representation
console.log(binary(42n)); // "0000000000000000000000000000000000000000000000000000000000101010"
console.log(binary(42n, false)); // "101010"
extractBits(data, shift, length): bigint
Extracts a portion of bits from a number.
Parameters:
data(bigint | string | number): Source datashift(bigint): Starting bit position (0-based from right)length(bigint): Number of bits to extract
Returns: BigInt - Extracted bits as number
const bits = extractBits(0b11110000n, 4n, 4n); // Extract 4 bits starting at position 4
console.log(bits); // 15n (0b1111)
Constants
SIMPLEFLAKE_EPOCH: number
The epoch start time (January 1, 2000 UTC) as Unix timestamp.
import { SIMPLEFLAKE_EPOCH } from 'simpleflakes';
console.log(SIMPLEFLAKE_EPOCH); // 946684800000
TypeScript Types
interface SimpleflakeStruct {
timestamp: bigint; // Unix timestamp as bigint (since 2000)
randomBits: bigint; // Random component as bigint
}
Migration Guide
From UUID
// Before (UU
