npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@toolkit-f/snowflake-id

v1.0.3

Published

Unique ID Generator For NodeJS

Readme

Snowflake-ID

Snowflake IDs are 64-bit unique identifiers. Sortable by time and can be generated across multiple servers without coordination and collision.

| 41 bits - Timestamp | 10 bits - Machine ID | 12 bits - Sequence |

Features

  • Generates unique IDs across distributed systems
  • Works with CommonJS and ESM
  • Full TypeScript support
  • Parse IDs to extract timestamp, machine ID, and sequence

Why Snowflake-ID?

| Feature | Snowflake ID | UUID v7 | UUID v4 | Auto Increment | |---------|--------------|---------|---------|----------------| | Sortable | Yes (Time) | Yes (Time) | No | Yes | | Unique | Distributed | Global | Global | Single DB | | DB Size | 8 bytes (BigInt) | 16 bytes (Bytes) | 16 bytes | 4/8 bytes | | Index | Fast (B-Tree) | Fast (B-Tree) | Slow (Fragmented) | Fast | | Performance | ~3M ops/sec | ~2M ops/sec | ~5M ops/sec | Database Limit | | Coordination | None | None | None | Centralized |

Perf Check: This library generates ~3 million IDs per second on a standard laptop (M1 Air).


Installation

npm

npm install @toolkit-f/snowflake-id

Yarn

yarn add @toolkit-f/snowflake-id

pnpm

pnpm add @toolkit-f/snowflake-id

Bun

bun add @toolkit-f/snowflake-id

Quick Start

Generate IDs

import { SnowflakeGenerator } from '@toolkit-f/snowflake-id';

// Create a generator with a unique machine ID (0-1023)
const generator = new SnowflakeGenerator({ machineId: 1 });

// Generate as BigInt
const id = generator.nextId();
console.log(id);  // 136941813297541120n

// Generate as String (recommended for JSON/APIs)
const idString = generator.nextIdString();
console.log(idString);  // "136941813297541121"

Parse Existing IDs

import { parseSnowflake } from '@toolkit-f/snowflake-id';

const parts = parseSnowflake('136941813297545217');
console.log(parts);
// {
//   id: 136941813297545217n,
//   timestamp: 2024-01-16T09:09:25.000Z,
//   machineId: 1,
//   sequence: 1
// }

CommonJS Support

const { SnowflakeGenerator } = require('@toolkit-f/snowflake-id');

const generator = new SnowflakeGenerator({ machineId: 1 });
console.log(generator.nextIdString());

Production Guide

1. Database Storage & BigInt Warning

⚠️ Important: Always use .nextIdString() for databases and APIs. JavaScript's Number type cannot safely hold 64-bit integers. IDs will lose precision and become incorrect if you cast them to Number

// BAD - Precision loss guarantees bugs
const id = generator.nextId();
const numericId = Number(id); 

// GOOD - Always treat as string
const stringId = generator.nextIdString();

PostgreSQL

Use BIGINT to store IDs efficiently.

CREATE TABLE users (
  id BIGINT PRIMARY KEY,
  username TEXT
);
// Correct: Pass as string, driver handles BIGINT conversion
const id = generator.nextIdString();
await db.query('INSERT INTO users (id, username) VALUES ($1, $2)', [id, 'alice']);

MySQL

Use BIGINT (64-bit integer).

CREATE TABLE orders (
  id BIGINT PRIMARY KEY,
  amount DECIMAL(10, 2)
);

MongoDB

Store as String to ensure compatibility with all clients.

const id = generator.nextIdString();
await collection.insertOne({ _id: id, ... });

Common Mistakes

| Mistake | Consequence | Fix | |---------|-------------|-----| | Number(id) | Data Corruption | Use String(id) or BigInt | | machineId: 0 everywhere | ID Collisions | Unique ID per instance | | Math.random() for ID | No Sorting | Use Snowflake |

Framework Integrations

NestJS

// snowflake.provider.ts
import { Provider } from '@nestjs/common';
import { SnowflakeGenerator } from '@toolkit-f/snowflake-id';

export const SNOWFLAKE_PROVIDER = 'SNOWFLAKE_GENERATOR';

export const snowflakeProvider: Provider = {
  provide: SNOWFLAKE_PROVIDER,
  useFactory: () => {
    const machineId = parseInt(process.env.MACHINE_ID || '0', 10);
    return new SnowflakeGenerator({ machineId });
  },
};

Prisma

// schema.prisma
model User {
  id        BigInt   @id
  username  String
}

Note: You must generate the ID in code before creating the record.

TypeORM

@Entity()
export class User {
  @PrimaryColumn('bigint')
  id: string; // TypeORM handles BigInt as string
}

2. Distributed Deployment (machineId)

To prevent ID collisions, every running instance must have a unique machineId (0-1023).

Kubernetes (StatefulSet)

Use the collection ordinal from the hostname (e.g., web-0, web-1).

const podName = process.env.HOSTNAME || 'web-0';
const machineId = parseInt(podName.split('-').pop() || '0', 10);
const generator = new SnowflakeGenerator({ machineId });

Docker Swarm / Replicas

Inject via environment variables:

services:
  api:
    environment:
      - MACHINE_ID={{.Task.Slot}}
const machineId = parseInt(process.env.MACHINE_ID || '0', 10);
const generator = new SnowflakeGenerator({ machineId });

Auto-scaling Groups

Options:

  1. Coordination Service: Use Redis/etcd to lease machineIds
  2. Hash-based: Hash instance ID to 0-1023 range (collision possible)
  3. Time-based: Use startup timestamp modulo 1024 (not recommended)

Multi-Region

Partition machineId ranges by region:

| Region | machineId Range | |--------|----------------| | us-east | 0-255 | | us-west | 256-511 | | eu-west | 512-767 | | ap-south | 768-1023 |

3. Security Considerations

⚠️ Snowflake IDs allow public timestamp decoding. Anyone with the ID can calculate exactly when a record was created.

const { parseSnowflake } = require('@toolkit-f/snowflake-id');
console.log(parseSnowflake('136941813297545217').timestamp);
// 2024-01-16T09:09:25.000Z
  • Do not use Snowflake IDs if the creation time must remain secret.
  • Do not trust the timestamp for security verification (it can be spoofed by the client if they generate IDs).
  • Consider using a separate random slug (e.g., UUID or NanoID) for public-facing URLs if business metrics (like order volume) need to be hidden.

API Reference

Core Class: SnowflakeGenerator

Constructor

new SnowflakeGenerator(config: SnowflakeConfig)

| Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | machineId | number | Yes | - | Unique ID for this machine/worker (0-1023) | | epoch | number | No | 1704067200000 (Jan 1, 2024) | Custom epoch in milliseconds | | clockMoveBackAction | 'throw' | 'wait' | No | 'throw' | Behavior when system clock drifts backwards |

Example:

import { SnowflakeGenerator } from '@toolkit-f/snowflake-id';

const generator = new SnowflakeGenerator({
  machineId: 5,
  epoch: 1609459200000,        // Jan 1, 2021
  clockMoveBackAction: 'wait'  // Wait instead of throwing error
});

nextId(): bigint

Generates the next unique ID as a bigint.

const generator = new SnowflakeGenerator({ machineId: 1 });

console.log(generator.nextId());
// 136941813297541120n

console.log(generator.nextId());
// 136941813297541121n

console.log(generator.nextId());
// 136941813297545216n

nextIdString(): string

Generates the next unique ID as a string.

const generator = new SnowflakeGenerator({ machineId: 1 });

console.log(generator.nextIdString());
// "136941813297541120"

console.log(generator.nextIdString());
// "136941813297541121"

getMachineId(): number

Returns the configured machine ID.

const generator = new SnowflakeGenerator({ machineId: 42 });

console.log(generator.getMachineId());
// 42

getEpoch(): number

Returns the configured epoch timestamp.

const generator = new SnowflakeGenerator({ machineId: 1 });

console.log(generator.getEpoch());
// 1704067200000

getSequence(): number

Returns the current sequence number.

const generator = new SnowflakeGenerator({ machineId: 1 });

generator.nextId();
console.log(generator.getSequence());
// 0

generator.nextId();
console.log(generator.getSequence());
// 1

getLastTimestamp(): number

Returns the timestamp of the last generated ID.

const generator = new SnowflakeGenerator({ machineId: 1 });

generator.nextId();
console.log(generator.getLastTimestamp());
// 1737017365000

Factory Function: createGenerator

createGenerator(config: SnowflakeConfig): SnowflakeGenerator

Alternative way to create a generator instance.

import { createGenerator } from '@toolkit-f/snowflake-id';

const generator = createGenerator({ machineId: 1 });

console.log(generator.nextId());
// 136941813297541120n

Utility Functions

parseSnowflake(id, epoch?): SnowflakeParts

Deconstructs a Snowflake ID into its components.

| Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | id | bigint | string | Yes | - | The Snowflake ID to parse | | epoch | number | No | 1704067200000 | Custom epoch used during generation |

Returns: SnowflakeParts

import { parseSnowflake } from '@toolkit-f/snowflake-id';

const parts = parseSnowflake('136941813297545217');
console.log(parts);
// {
//   id: 136941813297545217n,
//   timestamp: 2024-01-16T09:09:25.000Z,
//   timestampMs: 1737017365000,
//   machineId: 1,
//   sequence: 1
// }

const parts2 = parseSnowflake(136941813297545217n);
console.log(parts2);
// {
//   id: 136941813297545217n,
//   timestamp: 2024-01-16T09:09:25.000Z,
//   timestampMs: 1737017365000,
//   machineId: 1,
//   sequence: 1
// }

stringifySnowflakeParts(parts): SnowflakePartsJSON

Converts SnowflakeParts to a JSON-serializable format.

import { parseSnowflake, stringifySnowflakeParts } from '@toolkit-f/snowflake-id';

const parts = parseSnowflake('136941813297545217');
const json = stringifySnowflakeParts(parts);

console.log(json);
// {
//   id: "136941813297545217",
//   timestamp: "2024-01-16T09:09:25.000Z",
//   timestampMs: 1737017365000,
//   machineId: 1,
//   sequence: 1
// }

console.log(JSON.stringify(json));
// '{"id":"136941813297545217","timestamp":"2024-01-16T09:09:25.000Z","timestampMs":1737017365000,"machineId":1,"sequence":1}'

getTimestamp(id, epoch?): Date

Extracts the Date object from a Snowflake ID.

| Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | id | bigint | string | Yes | - | The Snowflake ID | | epoch | number | No | 1704067200000 | Custom epoch |

import { getTimestamp } from '@toolkit-f/snowflake-id';

console.log(getTimestamp('136941813297545217'));
// 2024-01-16T09:09:25.000Z

console.log(getTimestamp(136941813297545217n));
// 2024-01-16T09:09:25.000Z

getMachineId(id): number

Extracts the machine ID from a Snowflake ID.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | id | bigint | string | Yes | The Snowflake ID |

import { getMachineId } from '@toolkit-f/snowflake-id';

console.log(getMachineId('136941813297545217'));
// 1

console.log(getMachineId(136941813297545217n));
// 1

getSequence(id): number

Extracts the sequence number from a Snowflake ID.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | id | bigint | string | Yes | The Snowflake ID |

import { getSequence } from '@toolkit-f/snowflake-id';

console.log(getSequence('136941813297545217'));
// 1

console.log(getSequence(136941813297545217n));
// 1

isValidSnowflake(id, epoch?, relaxed?): boolean

Validates if a value is a valid Snowflake ID.

| Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | id | unknown | Yes | - | Value to validate | | epoch | number | No | 1704067200000 | Custom epoch | | relaxed | boolean | No | false | Skip timestamp range check |

import { isValidSnowflake } from '@toolkit-f/snowflake-id';

console.log(isValidSnowflake('136941813297545217'));
// true

console.log(isValidSnowflake(136941813297545217n));
// true

console.log(isValidSnowflake('invalid'));
// false

console.log(isValidSnowflake('abc123'));
// false

console.log(isValidSnowflake(-1n));
// false

// Relaxed mode (skip timestamp validation)
console.log(isValidSnowflake('999999999999999999999', undefined, true));
// true

snowflakeToString(id): string

Converts a bigint Snowflake ID to string.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | id | bigint | Yes | The Snowflake ID |

import { snowflakeToString } from '@toolkit-f/snowflake-id';

console.log(snowflakeToString(136941813297545217n));
// "136941813297545217"

stringToSnowflake(str): bigint

Converts a string Snowflake ID to bigint.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | str | string | Yes | The Snowflake ID string |

import { stringToSnowflake } from '@toolkit-f/snowflake-id';

console.log(stringToSnowflake('136941813297545217'));
// 136941813297545217n

// Throws error for invalid input
stringToSnowflake('invalid');
// Error: Invalid Snowflake ID string: "invalid"

compareSnowflakes(a, b): -1 | 0 | 1

Compares two Snowflake IDs. Useful for sorting.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | a | bigint | string | Yes | First Snowflake ID | | b | bigint | string | Yes | Second Snowflake ID |

Returns: -1 if a < b, 0 if a === b, 1 if a > b

import { compareSnowflakes } from '@toolkit-f/snowflake-id';

console.log(compareSnowflakes('136941813297545216', '136941813297545217'));
// -1

console.log(compareSnowflakes('136941813297545217', '136941813297545217'));
// 0

console.log(compareSnowflakes('136941813297545218', '136941813297545217'));
// 1

// Sorting example
const ids = ['136941813297545218', '136941813297545216', '136941813297545217'];
ids.sort(compareSnowflakes);
console.log(ids);
// ['136941813297545216', '136941813297545217', '136941813297545218']

snowflakeFromTimestamp(date, machineId?, sequence?, epoch?): bigint

Creates a Snowflake ID from a specific timestamp. Useful for database range queries.

| Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | date | Date | number | Yes | - | Timestamp to create ID from | | machineId | number | No | 0 | Machine ID (0-1023) | | sequence | number | No | 0 | Sequence number (0-4095) | | epoch | number | No | 1704067200000 | Custom epoch |

import { snowflakeFromTimestamp } from '@toolkit-f/snowflake-id';

// From Date object
const id1 = snowflakeFromTimestamp(new Date('2024-06-15T12:00:00.000Z'));
console.log(id1);
// 59918327808000000n

// From timestamp number
const id2 = snowflakeFromTimestamp(1718452800000);
console.log(id2);
// 59918327808000000n

// With machine ID and sequence
const id3 = snowflakeFromTimestamp(new Date('2024-06-15T12:00:00.000Z'), 5, 10);
console.log(id3);
// 59918327808020490n

// Database range query example
const startOfDay = snowflakeFromTimestamp(new Date('2024-06-15T00:00:00.000Z'));
const endOfDay = snowflakeFromTimestamp(new Date('2024-06-15T23:59:59.999Z'));
console.log(`SELECT * FROM items WHERE id >= ${startOfDay} AND id <= ${endOfDay}`);
// SELECT * FROM items WHERE id >= 59914215014400000 AND id <= 60010106326016000

Exported Constants

import {
  DEFAULT_EPOCH,
  MAX_MACHINE_ID,
  MAX_SEQUENCE,
  MACHINE_ID_SHIFT,
  TIMESTAMP_SHIFT
} from '@toolkit-f/snowflake-id';

console.log(DEFAULT_EPOCH);
// 1704067200000 (Jan 1, 2024 00:00:00 UTC)

console.log(MAX_MACHINE_ID);
// 1023

console.log(MAX_SEQUENCE);
// 4095n

console.log(MACHINE_ID_SHIFT);
// 12n

console.log(TIMESTAMP_SHIFT);
// 22n

TypeScript Types

import type {
  SnowflakeConfig,
  SnowflakeParts,
  SnowflakePartsJSON
} from '@toolkit-f/snowflake-id';

// SnowflakeConfig
interface SnowflakeConfig {
  machineId: number;              // 0-1023
  epoch?: number;                 // Custom epoch (ms)
  clockMoveBackAction?: 'throw' | 'wait';
}

// SnowflakeParts
interface SnowflakeParts {
  id: bigint;
  timestamp: Date;
  timestampMs: number;
  machineId: number;
  sequence: number;
}

// SnowflakePartsJSON
interface SnowflakePartsJSON {
  id: string;
  timestamp: string;
  timestampMs: number;
  machineId: number;
  sequence: number;
}

Error Handling

import { SnowflakeGenerator, stringToSnowflake, parseSnowflake } from '@toolkit-f/snowflake-id';

// Invalid machine ID
try {
  new SnowflakeGenerator({ machineId: 2000 });
} catch (e) {
  console.log(e.message);
  // "machineId must be integer 0-1023, got 2000"
}

// Future epoch
try {
  new SnowflakeGenerator({ machineId: 1, epoch: Date.now() + 100000 });
} catch (e) {
  console.log(e.message);
  // "epoch cannot be in the future"
}

// Invalid string ID
try {
  stringToSnowflake('not-a-number');
} catch (e) {
  console.log(e.message);
  // 'Invalid Snowflake ID string: "not-a-number"'
}

// Invalid parse input
try {
  parseSnowflake('abc123');
} catch (e) {
  console.log(e.message);
  // 'Invalid Snowflake ID: "abc123"'
}

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

🪪 License

MIT © Toolkit-F