Skip to main content
Fluxer uses Snowflake IDs - a distributed, time-ordered identifier system based on Twitter’s Snowflake format. Every resource in Fluxer (users, guilds, channels, messages, etc.) is assigned a unique 64-bit unsigned integer ID.

Format Structure

A Snowflake ID is composed of three parts:
64 bits total:
├─ Timestamp (42 bits) - Milliseconds since Fluxer epoch
├─ Worker ID (10 bits)  - Process/instance identifier  
└─ Sequence (12 bits)   - Incremental counter per millisecond

Bit Allocation

ComponentBitsMaximum ValueDescription
Timestamp42~69 yearsMilliseconds since Fluxer epoch (January 1, 2015 00:00:00 UTC)
Worker ID101,023Unique identifier for the generating worker/process
Sequence124,095Per-millisecond counter to handle high-frequency generation
The Fluxer epoch is 1420070400000 (January 1, 2015 00:00:00 UTC). This epoch allows for approximately 69 years of unique IDs before overflow.

Generation

Basic Usage

import { generateSnowflake } from '@fluxer/snowflake';

// Generate with default worker ID (0)
const id = generateSnowflake();
console.log(id); // 175928847299117063n

// Generate with specific worker ID
const id2 = generateSnowflake(42);

Generator Instance

For high-throughput scenarios, use a persistent generator:
import { SnowflakeGenerator } from '@fluxer/snowflake';

const generator = new SnowflakeGenerator({
  workerId: 5,
  now: () => Date.now() // Optional: custom time source
});

const id1 = generator.generate();
const id2 = generator.generate();
const id3 = generator.generate();
Each worker must have a unique Worker ID (0-1023) to prevent ID collisions across distributed systems.

Custom Snowflakes

Create snowflakes with specific components:
import { createSnowflake } from '@fluxer/snowflake';

const customId = createSnowflake({
  timestamp: Date.now(),
  workerId: 7,
  sequence: 42
});

// Create from timestamp only
const timestampId = createSnowflakeFromTimestamp(Date.now());

Parsing and Utilities

Extract Timestamp

import { snowflakeToDate, parseSnowflake, extractTimestamp } from '@fluxer/snowflake';

const id = 175928847299117063n;

// Get Date object
const date = snowflakeToDate(id);
console.log(date); // 2020-01-15T14:23:45.678Z

// Parse all components
const parts = parseSnowflake(id);
console.log(parts);
// {
//   timestamp: Date(2020-01-15T14:23:45.678Z),
//   workerId: 3,
//   sequence: 1234
// }

// Extract timestamp from string ID
const timestamp = extractTimestamp('175928847299117063');

Comparison and Sorting

import { compare, sortBySnowflakeDesc } from '@fluxer/snowflake';

// Compare two snowflakes
const result = compare('123456789', '987654321');
// Returns: -1 (first is older), 0 (equal), or 1 (first is newer)

// Sort messages by ID (newest first)
const messages = [
  { id: '100', content: 'Old' },
  { id: '300', content: 'New' },
  { id: '200', content: 'Middle' }
];

const sorted = sortBySnowflakeDesc(messages);
// [{ id: '300', ... }, { id: '200', ... }, { id: '100', ... }]

Validation

import { isValidSnowflake } from '@fluxer/snowflake';

// Validate snowflake
const valid = isValidSnowflake(175928847299117063n);
console.log(valid); // true

// Invalid cases:
isValidSnowflake(-1n);        // false - negative
isValidSnowflake('invalid');  // false - not a bigint
isValidSnowflake(future);     // false - timestamp too far in future

Time-Based Operations

Age Calculation

import { age, ageBigInt } from '@fluxer/snowflake';

const messageId = '175928847299117063';
const ageMs = age(messageId);
console.log(`Message is ${ageMs}ms old`);

// With BigInt
const ageBigIntMs = ageBigInt(175928847299117063n);

Timestamp Navigation

import { 
  atNextMillisecond, 
  atPreviousMillisecond,
  fromTimestamp 
} from '@fluxer/snowflake';

// Get ID for next millisecond boundary
const nextId = atNextMillisecond('175928847299117063');

// Get ID for previous millisecond
const prevId = atPreviousMillisecond('175928847299117063');

// Create ID from specific timestamp
const id = fromTimestamp(Date.now());

Bucketing System

Fluxer uses buckets to partition snowflakes for efficient querying:
import { makeBucket, makeBuckets } from '@fluxer/snowflake';

// Get bucket for a single snowflake
const bucket = makeBucket(175928847299117063n);
console.log(bucket); // 203

// Get range of buckets between two IDs
const buckets = makeBuckets(
  startId,  // Start snowflake
  endId     // End snowflake
);
console.log(buckets); // [203, 204, 205]
Each bucket represents a 10-day time window. Buckets are used internally for database partitioning and efficient range queries.

Bucket Size

import { SNOWFLAKE_BUCKET_SIZE_MS } from '@fluxer/snowflake';

console.log(SNOWFLAKE_BUCKET_SIZE_MS); // 864000000 (10 days in ms)

Sequence Management

For advanced use cases requiring manual sequence control:
import { SnowflakeSequence } from '@fluxer/snowflake';

const sequence = new SnowflakeSequence({ initialValue: 0 });

// Get next sequence number
const seq1 = sequence.next(); // 0
const seq2 = sequence.next(); // 1

// Check current value
const current = sequence.peek(); // 2

// Check for overflow
if (sequence.willOverflowNext()) {
  sequence.reset(); // Reset to 0
}

Best Practices

Use BigInt

Always use BigInt (n suffix) for snowflakes in TypeScript/JavaScript to prevent precision loss with large integers.

Unique Worker IDs

Assign unique Worker IDs (0-1023) to each process/instance in distributed deployments to prevent ID collisions.

Time-Based Ordering

Snowflakes are naturally time-ordered. Use this property for efficient range queries and pagination.

Avoid Hardcoding

Never hardcode snowflake IDs. They are instance-specific and will differ across environments.

API Reference

Constants

ConstantTypeValueDescription
FLUXER_EPOCHbigint1420070400000nFluxer epoch in milliseconds
WORKER_ID_BITSbigint10nBits allocated for worker ID
SEQUENCE_BITSbigint12nBits allocated for sequence
MAX_WORKER_IDbigint1023nMaximum worker ID value
MAX_SEQUENCEbigint4095nMaximum sequence value
TIMESTAMP_SHIFTbigint22nBit shift for timestamp

Functions

generateSnowflake
function
Generate a new snowflake IDParameters:
  • workerIdOrOptions?: number | SnowflakeGeneratorOptions
Returns: bigint
createSnowflake
function
Create a snowflake from componentsParameters:
  • options: CreateSnowflakeOptions
Returns: bigint
parseSnowflake
function
Parse snowflake into componentsParameters:
  • snowflake: bigint
Returns: SnowflakeParts
isValidSnowflake
function
Validate a snowflake IDParameters:
  • value: unknown
Returns: boolean

Build docs developers (and LLMs) love