🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@cdlab996/genid

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@cdlab996/genid

High-performance distributed unique ID generator based on the Snowflake algorithm

latest
Source
npmnpm
Version
1.4.0
Version published
Weekly downloads
32
52.38%
Maintainers
1
Weekly downloads
 
Created
Source

@cdlab996/genid

npm version license

High-performance distributed unique ID generator based on the Snowflake algorithm, with drift mode and clock-rollback handling.

中文文档

Features

  • Drift Algorithm - Exceeds per-millisecond sequence limits under high concurrency for better throughput
  • Clock Rollback Handling - Graceful degradation using reserved sequence numbers without blocking ID generation
  • Flexible Configuration - Customize bit allocation for timestamp, worker ID, and sequence
  • ID Validation - Strict and loose validation modes with afterTime support
  • Runtime Monitoring - Built-in statistics, parsing, and binary formatting for debugging

Installation

# npm
npm install @cdlab996/genid

# pnpm
pnpm add @cdlab996/genid

Quick Start

import { GenidOptimized } from '@cdlab996/genid'

// Create an instance (use a different workerId for each worker/process)
const genid = new GenidOptimized({ workerId: 1 })

// Generate an ID
const id = genid.nextId()

// Batch generate
const ids = genid.nextBatch(1000)

// Parse an ID
const info = genid.parse(id)
// => { timestamp: Date, timestampMs: 1609459200000, workerId: 1, sequence: 42 }

// Validate an ID
genid.isValid(id) // true

API

new GenidOptimized(options)

ParameterTypeRequiredDefaultDescription
workerIdnumberYes-Worker node ID (0 to 2^workerIdBitLength-1)
methodGenidMethodDRIFTAlgorithm: DRIFT or TRADITIONAL
baseTimenumber1577836800000Base timestamp in ms (default: 2020-01-01)
workerIdBitLengthnumber6Bit length for worker ID (1-15)
seqBitLengthnumber6Bit length for sequence (3-21)
maxSeqNumbernumber2^seqBitLength-1Maximum sequence number
minSeqNumbernumber5Minimum sequence number (0-4 reserved for rollback)
topOverCostCountnumber2000Maximum drift count

Generating IDs

genid.nextId()             // Returns number | bigint (auto-selects)
genid.nextNumber()         // Returns number (throws if exceeds safe integer range)
genid.nextBigId()          // Returns bigint
genid.nextBatch(100)       // Batch generate 100 IDs
genid.nextBatch(100, true) // Batch generate 100 BigInt IDs

Parsing & Validation

// Parse an ID into its components
genid.parse(id)
// => { timestamp: Date, timestampMs: number, workerId: number, sequence: number }

// Loose validation: checks structural validity
genid.isValid(id)            // true
genid.isValid('invalid')     // false

// Strict validation: requires workerId to match the current instance
genid.isValid(id, true)      // true (generated by this instance)
genid.isValid(otherId, true) // false (generated by another instance)

// Time-bound validation: reject IDs generated before a given time
const startupTime = Date.now()
genid.isValid(id, { afterTime: startupTime })                       // true
genid.isValid(id, { strictWorkerId: true, afterTime: startupTime }) // combined

Statistics & Configuration

// Get runtime statistics
genid.getStats()
// => {
//   totalGenerated: 1000,
//   overCostCount: 10,
//   turnBackCount: 2,
//   uptimeMs: 60000,
//   avgPerSecond: 16,
//   currentState: 'NORMAL' | 'OVER_COST'
// }

// Get current configuration
genid.getConfig()
// => {
//   method: 'DRIFT',
//   workerId: 1,
//   workerIdRange: '0-63',
//   sequenceRange: '5-63',
//   maxSequence: 63,
//   idsPerMillisecond: 59,
//   baseTime: Date,
//   timestampBits: 52,
//   workerIdBits: 6,
//   sequenceBits: 6
// }

// Reset statistics
genid.resetStats()

Debugging

genid.formatBinary(id)
// ID: 123456789012345
// Binary (64-bit):
// 0000000000011010... - Timestamp (52 bits) = 2025-10-17T...
// 000001 - Worker ID (6 bits) = 1
// 101010 - Sequence (6 bits) = 42

Examples

Custom Bit Allocation

import { GenidOptimized, GenidMethod } from '@cdlab996/genid'

const genid = new GenidOptimized({
  workerId: 1,
  method: GenidMethod.TRADITIONAL,
  baseTime: new Date('2024-01-01').valueOf(),
  workerIdBitLength: 10, // Support 1024 nodes
  seqBitLength: 12,      // 4096 IDs per millisecond
  topOverCostCount: 5000,
})

Validating External IDs

// Validate IDs from a database or API
const externalId = '123456789012345'
if (genid.isValid(externalId)) {
  const info = genid.parse(externalId)
  console.log('Generated at:', info.timestamp)
  console.log('From worker:', info.workerId)
} else {
  console.error('Invalid ID')
}

Performance Monitoring

setInterval(() => {
  const stats = genid.getStats()
  console.log(`Rate: ${stats.avgPerSecond} ID/s | Drift: ${stats.overCostCount} | Rollback: ${stats.turnBackCount}`)
}, 10000)

Algorithm Modes

ModeDescriptionUse Case
DRIFT (default)Borrows future timestamps when sequence is exhausted; avoids waitsHigh-frequency ID generation
TRADITIONALStrictly increasing timestamps; waits for next ms on exhaustionStrict time-ordering required

Architecture

ID Structure (64-bit)

|------------ Timestamp ------------|-- Worker ID --|-- Sequence --|
        42-52 bits                      1-15 bits       3-21 bits

Default: Timestamp 52 bits (~139 years) | Worker ID 6 bits (64 nodes) | Sequence 6 bits (59 IDs/ms)

Sequence values 0-4 are reserved for clock rollback; normal generation starts at 5.

Core Flow

graph TB
    A[Start ID Generation] --> B{In drift mode?}

    B -->|No| C[Normal Path]
    B -->|Yes| D[Drift Path]

    C --> E{Check Clock}
    E -->|Clock Rollback| F[Use Reserved Sequence 0-4]
    E -->|Time Advanced| G[Reset Sequence]
    E -->|Same Millisecond| H{Sequence Exhausted?}

    H -->|No| I[Increment Sequence]
    H -->|Yes| J[Enter Drift Mode, Timestamp+1]

    D --> K{Check Time}
    K -->|Time Caught Up| L[Exit Drift, Resume Normal]
    K -->|Exceeded Max Drift| M[Wait for Next ms, Exit Drift]
    K -->|Continue Drift| N{Sequence Exhausted?}

    N -->|No| O[Use Current Sequence]
    N -->|Yes| P[Timestamp+1, Reset Sequence]

    F --> Q[Assemble ID]
    G --> Q
    I --> Q
    J --> Q
    L --> Q
    M --> Q
    O --> Q
    P --> Q

    Q --> R[Update Statistics]
    R --> S[Return ID]

Performance

Throughput is determined by the number of available sequence slots per millisecond. Increasing seqBitLength scales linearly:

seqBitLengthSlots/msThroughput
33~3,000 IDs/sec
411~11,000 IDs/sec
6 (default)59~58,000 IDs/sec
8251~247,000 IDs/sec
101,019~1,000,000 IDs/sec
1416,379~4,500,000 IDs/sec

Measured on Node.js v22 (x64). Actual results vary by environment. Run pnpm run benchmark to probe your own machine.

MetricValue (default config)
Max worker nodes64
Timestamp lifespan~139 years
P99 latency (single call)< 1µs

Benchmark

A built-in probe script measures the actual capability of the current environment:

pnpm run benchmark

It reports:

  • Single-call throughput — peak nextId() IDs/sec
  • Batch throughputnextBatch() across different batch sizes
  • Latency percentiles — P50 / P95 / P99 / P99.9 / Max
  • Algorithm comparison — DRIFT vs TRADITIONAL side-by-side
  • Throughput by seqBitLength — how bit allocation affects throughput
  • Memory footprint — heap delta after 1M generations
  • Recommended thresholds — suggested safe values for test assertions (60% of peak)
Example output
station :: /app/projects/genid ‹main*› » pnpm run benchmark

> @cdlab996/genid@1.4.0 benchmark /app/projects/genid
> npx tsx scripts/benchmark.ts

============================================================
  GenidOptimized — Environment Capability Probe
  Node v22.22.0 | linux x64
  Date: 2026-04-01T08:41:07.669Z
============================================================

────────────────────────────────────────────────────────────
  1. Single-call throughput (nextId)
────────────────────────────────────────────────────────────
  Duration:   3001ms
  Generated:  226,073
  Throughput: 75,332 IDs/sec

────────────────────────────────────────────────────────────
  2. Batch throughput (nextBatch)
────────────────────────────────────────────────────────────
  batch=    100 × 5000  =>        61,665 IDs/sec
  batch=  1,000 ×  500  =>        61,577 IDs/sec
  batch= 10,000 ×   50  =>        61,716 IDs/sec
  batch=100,000 ×    5  =>        61,644 IDs/sec

────────────────────────────────────────────────────────────
  3. Single-call latency percentiles
────────────────────────────────────────────────────────────
  Samples: 100,000
  Avg:     0µs
  P50:     0µs
  P95:     1µs
  P99:     1µs
  P99.9:   1µs
  Max:     364µs

────────────────────────────────────────────────────────────
  4. Algorithm comparison (DRIFT vs TRADITIONAL)
────────────────────────────────────────────────────────────
  DRIFT              58,296 IDs/sec   drift=1
  TRADITIONAL        59,000 IDs/sec   drift=0

────────────────────────────────────────────────────────────
  5. Throughput by sequence bit length
────────────────────────────────────────────────────────────
  seqBits= 3  maxSeq=    7  =>         2,986 IDs/sec   drift=1
  seqBits= 4  maxSeq=   15  =>        10,884 IDs/sec   drift=1
  seqBits= 6  maxSeq=   63  =>        58,240 IDs/sec   drift=1
  seqBits= 8  maxSeq=  255  =>       247,804 IDs/sec   drift=1
  seqBits=10  maxSeq= 1023  =>     1,008,930 IDs/sec   drift=1
  seqBits=14  maxSeq=16383  =>     4,130,701 IDs/sec   drift=0

────────────────────────────────────────────────────────────
  6. Memory footprint
────────────────────────────────────────────────────────────
  Generated:    1,000,000 IDs (not stored)
  Heap delta:   -6.27 MB
  Note: Run with --expose-gc for accurate GC-forced measurement

────────────────────────────────────────────────────────────
  Summary — Recommended test thresholds
────────────────────────────────────────────────────────────
  Peak single-call:        75,332 IDs/sec
  Peak batch:              61,716 IDs/sec
  Suggested min threshold: 45,199 IDs/sec  (60% of peak)
  Suggested batch threshold: 37,029 IDs/sec  (60% of peak)
  Suggested P99 cap:       2µs  (3× measured P99)

Development

pnpm install          # Install dependencies
pnpm run build        # Build (ESM + CJS)
pnpm run dev          # Watch mode
pnpm run test         # Run tests
pnpm run benchmark    # Run environment capability probe
pnpm run typecheck    # Type check
pnpm run lint         # Lint (Biome)
pnpm run format       # Format (Biome)

Notes

  • Each worker/process must use a unique workerId
  • Instances are not thread-safe — do not share across threads
  • workerIdBitLength + seqBitLength must not exceed 22
  • Sequence values 0-4 are reserved for clock-rollback handling
  • When IDs exceed the JavaScript safe integer range (2^53-1), use nextBigId() or nextId() (auto-returns BigInt)

License

MIT License © 2025-PRESENT wudi

Keywords

snowflake

FAQs

Package last updated on 01 Apr 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts