@code_with_sachin/uusid
v3.1.0
Published
Ultra Unique Secure ID generator with multiple formats, encryption, hierarchical IDs, and advanced features for modern applications
Maintainers
Readme
UUSID — Ultra Unique Secure ID
A modern UUID-shaped ID generator for Node.js and the browser, with multiple output formats, AES encryption, deterministic content-based IDs, hierarchical IDs, and zero runtime dependencies.
import { uusid } from '@code_with_sachin/uusid/browser'; // React / Angular / Next client / Vite
// or
const { uusid } = require('@code_with_sachin/uusid'); // Node, plain CommonJS
uusid(); // → "550e8400-e29b-41d4-a716-446655440000"Why UUSID
- One library, two runtimes. A Node entry that uses
node:cryptoand a browser entry that uses Web Crypto. Bundlers route automatically. - Drop-in UUID v1 layout. 36-char canonical format — works anywhere a UUID does.
- Batteries included. Prefixes, encryption, validation, batch analysis, hierarchical IDs, content-based IDs, metrics, and a CLI.
- Zero dependencies. Tiny install, no transitive surprises.
- TypeScript first. Full
.d.tsfor both server and browser entries.
Install
npm install @code_with_sachin/uusid
# or
pnpm add @code_with_sachin/uusid
# or
yarn add @code_with_sachin/uusidServer vs. Browser
Since v3.1.0 the package ships two explicit subpath entries plus a backwards-compatible root that points at the server build. The package.json exports map keeps them isolated, so SSR and CSR code in the same project never cross-contaminate.
| Import | Runtime | Module format | Crypto |
| --- | --- | --- | --- |
| @code_with_sachin/uusid (root) | Node ≥ 14 | CJS | node:crypto |
| @code_with_sachin/uusid/server | Node ≥ 14 | CJS | node:crypto |
| @code_with_sachin/uusid/browser | All evergreen browsers, Node ≥ 18 | ESM | Web Crypto (globalThis.crypto) |
// React / Angular / Next.js client component / Vite / Svelte / Solid
import { uusid, validate } from '@code_with_sachin/uusid/browser';
// Next.js Route Handler / Server Component / Express / plain Node
import { uusid } from '@code_with_sachin/uusid/server';
// equivalent to:
const { uusid } = require('@code_with_sachin/uusid');What's different on the browser entry
fromContent,encrypt,decrypt, andEncryptedGenerator.generate()areasync(Web Crypto'ssubtle.digest/subtle.encrypt/subtle.decryptare Promise-based). Server keeps the synchronous signatures.WorkerPoolandcreateWorkerPoolare not exported in the browser. Use the server entry for very high-volume generation, or run the browser entry inside a Web Worker yourself.getMetrics()andhealthCheck()omit thememoryUsagefield — there is noprocess.memoryUsagein browsers.- The browser entry uses AES-256-GCM for
encrypt/decrypt. The server entry uses AES-256-CBC. Encrypted IDs are not portable across the two entries — encrypt and decrypt with the same one.
Framework recipes
React + Vite
// src/UserCard.jsx
import { uusid } from '@code_with_sachin/uusid/browser';
export function UserCard({ name }) {
const [id] = useState(() => uusid());
return <div data-id={id}>{name}</div>;
}Next.js (App Router)
// app/api/users/route.ts — server, sync
import { uusid } from '@code_with_sachin/uusid/server';
export async function POST(req: Request) {
const id = uusid();
return Response.json({ id });
}// app/components/Button.tsx — client component
'use client';
import { uusid } from '@code_with_sachin/uusid/browser';
export default function Button() {
return <button data-trace={uusid()}>Click</button>;
}Angular
// src/app/id.service.ts
import { Injectable } from '@angular/core';
import { uusid, fromContent } from '@code_with_sachin/uusid/browser';
@Injectable({ providedIn: 'root' })
export class IdService {
next() { return uusid(); }
forContent(content: string) { return fromContent(content); } // async
}Express
const express = require('express');
const { uusid } = require('@code_with_sachin/uusid'); // bare = server
const app = express();
app.use((req, _res, next) => { req.requestId = uusid(); next(); });API reference
Top-level functions
| Export | Server | Browser | Returns |
| --- | --- | --- | --- |
| uusid(options?) | sync | sync | string |
| uusidBatch(count, options?) | sync | sync | string[] |
| validate(id, options?) | sync | sync | ValidationResult |
| extractTimestamp(id) | sync | sync | number (ms) |
| isInTimeRange(id, start, end) | sync | sync | boolean |
| analyze(idArray) | sync | sync | AnalysisResult |
| getMetrics() | sync | sync | Metrics |
| healthCheck() | async | async | Promise<HealthCheck> |
| base32() | sync | sync | string (26 chars) |
| urlSafe() | sync | sync | string (32 chars, lowercase) |
| compact() | sync | sync | string (32 chars) |
| hierarchical(options?) | sync | sync | string (dotted) |
| fromContent(content, options?) | sync | async | string / Promise<string> |
Classes
| Export | Notes |
| --- | --- |
| UUSIDGenerator | Core class. All instance methods mirror the top-level functions. |
| PrefixedGenerator(prefix, options?) | Auto-prefixes every ID. Uses _ as the separator. |
| EncryptedGenerator({ secretKey, ... }) | generate() returns an encrypted ID. Async on browser. |
| WorkerPool({ workers, batchSize }) | Server only. Multi-instance batch generation. |
Factory helpers
createGenerator, createPrefixedGenerator, createEncryptedGenerator, createWorkerPool — thin wrappers that return new class instances.
ID formats
import {
uusid, base32, urlSafe, compact, hierarchical
} from '@code_with_sachin/uusid/browser';
uusid(); // "550e8400-e29b-41d4-a716-446655440000" (36 chars, canonical)
compact(); // "550e8400e29b41d4a716446655440000" (32 chars, no separators)
urlSafe(); // "550e8400e29b41d4a716446655440000" (lowercased compact)
base32(); // "KRSXG5CTMZRW6Z3JN5XGK4TLAA" (26 chars)
hierarchical(); // "550e8400e2.9b41d4a716.446655440000" (3 dotted levels)
hierarchical({ parent: 'org.team' });
// "org.team.550e8400e2" (child of a parent)Output values are illustrative — your IDs will differ.
Generators
Default
import { createGenerator } from '@code_with_sachin/uusid/server';
const gen = createGenerator({
prefix: 'order',
separator: '_',
validAfter: '2025-01-01',
validBefore: '2026-12-31',
});
gen.generate(); // "order_550e8400_e29b_41d4_a716_446655440000"
gen.generateBatch(10); // string[]
gen.generateSortedBatch(10); // chronologically sortedPrefixed
import { createPrefixedGenerator } from '@code_with_sachin/uusid/server';
const users = createPrefixedGenerator('user');
users.generate(); // "user_550e8400_e29b_41d4_a716_446655440000"
PrefixedGeneratoralways uses_as the separator. UsecreateGenerator({ prefix, separator })if you need a different one.
Encrypted
// Server — sync
import { createEncryptedGenerator } from '@code_with_sachin/uusid/server';
const sec = createEncryptedGenerator({ secretKey: process.env.SECRET });
const ct = sec.generate(); // "ivHex:cipherTextHex" (AES-256-CBC)
const pt = sec.decrypt(ct); // recovered uusid
// Browser — async, AES-256-GCM
import { createEncryptedGenerator } from '@code_with_sachin/uusid/browser';
const sec = createEncryptedGenerator({ secretKey: 'k'.repeat(32) });
const ct = await sec.generate();
const pt = await sec.decrypt(ct);Content-based (deterministic)
Same content → same ID. Useful as a stable derived key.
import { fromContent } from '@code_with_sachin/uusid/server'; // sync
fromContent('[email protected]'); // "8c12...-...-...-...-..."
fromContent('[email protected]', { namespace: 'users', algorithm: 'sha256' });import { fromContent } from '@code_with_sachin/uusid/browser'; // async
await fromContent('[email protected]');
await fromContent('[email protected]', { namespace: 'users', algorithm: 'SHA-256' });Note: server uses Node's algorithm names (
'sha256'); browser uses Web Crypto names ('SHA-256').
Worker pool (server only)
const { createWorkerPool } = require('@code_with_sachin/uusid');
const pool = createWorkerPool({ workers: 8, batchSize: 1_000 });
const ids = await pool.generateBatch(50_000);Validation, analysis, metrics
import { validate, analyze, extractTimestamp, isInTimeRange,
getMetrics, healthCheck, uusid } from '@code_with_sachin/uusid';
const id = uusid();
validate(id);
// { valid: true, isValid: true, version: 'uusid', entropy: 3.7 }
extractTimestamp(id); // 1735689600000 (ms since epoch)
isInTimeRange(id, '2025-01-01', '2026-01-01'); // true / false
analyze([uusid(), uusid(), 'not-an-id']);
// {
// total: 3, totalIds: 3,
// valid: 2, invalid: 1, duplicates: 0, uniqueIds: 3,
// timeRange: { earliest: Date, latest: Date },
// formats: { standard: 2, prefixed: 0, custom: 0 },
// errors: ['Invalid ID not-an-id: Invalid format']
// }
getMetrics();
// { totalGenerated, uptime, averageRate, currentRate, peakRate,
// collisions, memoryUsage } // memoryUsage is server-only
await healthCheck();
// { healthy: true, checks: { validation, uniqueness, performance },
// metrics: { generationTime, rate }, timestamp }Hierarchical IDs
import { hierarchical, createGenerator } from '@code_with_sachin/uusid';
const root = hierarchical(); // "aaaaaaaa.bbbbbbbb.ccccccccdddd"
const child = hierarchical({ parent: root }); // "<root>.eeeeeeeeff"
const gen = createGenerator();
gen.parseHierarchy(child);
// { depth: 1, parts: [...], parent: <root>, root: <first 3 parts>, leaf: 'eeeeeeeeff' }CLI
npm install -g @code_with_sachin/uusid# Generate
uusid generate --count 10 --format base32
uusid gen -c 5 -f url-safe --prefix API
# Validate / inspect
uusid validate 550e8400-e29b-41d4-a716-446655440000
uusid analyze ids.txt
# Diagnostics
uusid benchmark --iterations 100000
uusid health
uusid metricsTypeScript
Types ship with the package. Both subpaths have their own .d.ts, so the async surface differences on /browser are reflected in your editor.
import { uusid, UUSIDGenerator, ValidationResult } from '@code_with_sachin/uusid/server';
const gen: UUSIDGenerator = new UUSIDGenerator({ prefix: 'usr', separator: '-' });
const id: string = uusid();
const v: ValidationResult = gen.validate(id);import { fromContent } from '@code_with_sachin/uusid/browser';
const id: string = await fromContent('hello'); // Promise<string> on /browserPerformance
Measured locally with npm run benchmark on Node 24 / Apple Silicon. Numbers are indicative.
| Operation | Throughput | Notes |
| --- | --- | --- |
| uusid() (default generator) | ~6,000–60,000 ops/sec | Single-thread, includes timestamp + clock-seq logic |
| WorkerPool.generateBatch() | 60,000+ ops/sec | Multi-instance, server only |
| validate() | 10M+ ops/sec | Pure regex + math |
| fromContent() (server, SHA-256) | 750k+ ops/sec | One hash per call |
| EncryptedGenerator.generate() (server, AES-CBC) | 50k+ ops/sec | Includes encryption |
Memory: ~50 bytes per ID retained, no internal queues, no leaks observed across 500k generations. Collision resistance: zero collisions across 500k generations in test suite.
Migration
From uuid
// Before
const { v4: uuidv4 } = require('uuid');
const id = uuidv4();
// After
const { uusid } = require('@code_with_sachin/uusid');
const id = uusid();From crypto.randomBytes
// Before
const id = require('crypto').randomBytes(16).toString('hex');
// After — same shape, plus prefixing/encryption/etc when you need them
const { compact } = require('@code_with_sachin/uusid');
const id = compact();From v3.0.x → v3.1.0
No breaking changes. Existing require('@code_with_sachin/uusid') and import from the bare path keep working unchanged. The new /server and /browser subpaths are additive.
Development
npm test # 19 server-side tests
npm run test:browser # 20 browser-entry tests (uses globalThis.crypto)
npm run benchmark # performance numbers
npm run example # walkthrough of every featureRoadmap
- [x] Browser compatibility (v3.1.0)
- [x] Subpath imports (
/server,/browser) - [ ] AES-256-GCM on the server entry (cross-runtime encrypted ID interop)
- [ ] Web Worker port of
WorkerPool - [ ] Pluggable RNG hooks
- [ ] Optional URL-safe Base64 format
Contributing
Issues and pull requests are welcome at https://github.com/CodeWithSachin/uusid. Please run npm test && npm run test:browser before submitting.
License
ISC — see LICENSE.
Related
Made by Sachin Singh. If this saves you time, a star on GitHub is appreciated.
