uuid
PoolZero-dependency UUID library - Modern, tree-shakeable alternative to uuid package
@lpm.dev/neo.uuid
Modern, zero-dependency UUID library for Node.js 18+ and browsers.
Features
- ✅ Zero runtime dependencies - no external packages
- ✅ TypeScript-first - strict mode with full type safety
- ✅ Tree-shakeable - import only what you need (v4 only = ~0.1 KB)
- ✅ Modern focus - UUID v4 (random), v7 (time-ordered), v5 (deterministic)
- ✅ RFC 9562 compliant - follows latest UUID specification (May 2024)
- ✅ High performance - 10M+ ops/sec for v4, competitive across the board
- ✅ Validation & parsing - format validation, version detection, binary conversion
- ✅ Timestamp extraction - extract timestamps from UUID v7
- ✅ 130+ tests - comprehensive test coverage
Installation
lpm install @lpm.dev/neo.uuidQuick Start
import { uuidv4, uuidv7 } from "@lpm.dev/neo.uuid";
// UUID v4 (random)
const id = uuidv4();
// '550e8400-e29b-41d4-a716-446655440000'
// UUID v7 (time-ordered, sortable)
const timeId = uuidv7();
// '018f3e7a-8c5a-7000-8000-123456789abc'Why neo.uuid?
| Feature | neo.uuid | uuid package | nanoid |
|---|---|---|---|
| Bundle size (v4 only) | ~0.1 KB | ~0.4 KB | ~0.1 KB |
| Bundle size (all features) | ~5.7 KB | ~6-7 KB | ~0.1 KB |
| Tree-shakeable | ✅ | ⚠️ (requires care) | ✅ |
| TypeScript-first | ✅ | ✅ | ✅ |
| Zero dependencies | ✅ | ✅ | ✅ |
| RFC-compliant UUIDs | ✅ | ✅ | ❌ |
| UUID v7 support | ✅ | ✅ | N/A |
| Validation utilities | ✅ | ✅ | ❌ |
| Timestamp extraction | ✅ | ❌ | N/A |
| v4 performance | 10.1M ops/s | 6.4M ops/s | 5.3M ops/s |
When to use neo.uuid:
- Need RFC-compliant UUIDs with modern features
- Want time-ordered UUIDs (v7) for better database performance
- Need validation and parsing utilities
- Prefer TypeScript-first libraries with strict typing
- Want tree-shakeable imports to minimize bundle size
When to use alternatives:
- nanoid: Need smallest possible bundle (~0.1 KB) and don't need RFC compliance
- uuid package: Need legacy UUID versions (v1, v3, v6, v8) or synchronous v5
API Reference
UUID Generation
uuidv4()
Generate UUID v4 (random). Uses native crypto.randomUUID() for maximum performance.
import { uuidv4 } from "@lpm.dev/neo.uuid";
const id = uuidv4();
// '550e8400-e29b-41d4-a716-446655440000'Performance: 10.1M ops/sec (1.57x faster than uuid package)
uuidv7(options?)
Generate UUID v7 (time-ordered). Includes 48-bit millisecond timestamp with monotonic counter.
import { uuidv7 } from "@lpm.dev/neo.uuid";
const id = uuidv7();
// '018f3e7a-8c5a-7000-8000-123456789abc'
// With custom timestamp (for testing)
const customId = uuidv7({ timestamp: Date.now() });Why UUID v7?
- Sortable: Lexicographically ordered by time
- Database-friendly: Reduces index fragmentation vs random UUIDs
- Time-embedded: Contains accurate millisecond timestamp
- Modern standard: Part of RFC 9562 (May 2024)
Performance: 878K ops/sec
Options:
timestamp?: number- Custom timestamp in milliseconds (default:Date.now())randomBytes?: Uint8Array- Custom random bytes for testing
uuidv5(name, namespace)
Generate UUID v5 (deterministic, SHA-1 namespace-based). Same input always produces same output.
import { uuidv5, NAMESPACE_DNS } from "@lpm.dev/neo.uuid";
// Async version (uses Web Crypto API)
const id = await uuidv5("example.com", NAMESPACE_DNS);
// '9073926b-929f-5ca9-bbc5-bd60baa5c5e3'
// Always returns same UUID for same input
const id2 = await uuidv5("example.com", NAMESPACE_DNS);
// '9073926b-929f-5ca9-bbc5-bd60baa5c5e3' (same)
// Sync version (Node.js only)
import { uuidv5Sync } from "@lpm.dev/neo.uuid";
const syncId = uuidv5Sync("example.com", NAMESPACE_DNS);Use cases:
- Generate consistent UUIDs from existing identifiers
- Create reproducible UUIDs in tests
- Derive UUIDs from domain names, URLs, or other namespaces
Performance: 71K ops/sec (async), varies for sync
Namespaces:
NAMESPACE_DNS- Domain names (e.g., 'example.com')NAMESPACE_URL- URLs (e.g., 'https://example.com')NAMESPACE_OID- ISO Object IDsNAMESPACE_X500- X.500 Distinguished Names
Validation
validate(uuid, version?)
Validate UUID format and optionally check version.
import { validate } from "@lpm.dev/neo.uuid";
validate("550e8400-e29b-41d4-a716-446655440000"); // true
validate("550e8400-e29b-41d4-a716-446655440000", 4); // true (v4)
validate("550e8400-e29b-41d4-a716-446655440000", 7); // false (not v7)
validate("not-a-uuid"); // falsePerformance: 9.4M ops/sec
Parameters:
uuid: string- UUID string to validateversion?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8- Optional version to validate against
version(uuid)
Detect UUID version (1-8).
import { version } from "@lpm.dev/neo.uuid";
version("550e8400-e29b-41d4-a716-446655440000"); // 4
version("018f3e7a-8c5a-7000-8000-123456789abc"); // 7
version("not-a-uuid"); // nullPerformance: 8.1M ops/sec (1.40x faster than uuid package)
Parsing & Conversion
parse(uuid)
Convert UUID string to 16-byte Uint8Array.
import { parse } from "@lpm.dev/neo.uuid";
const bytes = parse("550e8400-e29b-41d4-a716-446655440000");
// Uint8Array(16) [85, 14, 132, 0, 226, 155, 65, 212, 167, 22, 68, 102, 85, 68, 0, 0]Performance: 1.3M ops/sec
Throws: Error if invalid UUID format
stringify(bytes)
Convert 16-byte Uint8Array to UUID string.
import { stringify } from "@lpm.dev/neo.uuid";
const bytes = new Uint8Array([
85, 14, 132, 0, 226, 155, 65, 212, 167, 22, 68, 102, 85, 68, 0, 0,
]);
const uuid = stringify(bytes);
// '550e8400-e29b-41d4-a716-446655440000'Performance: 1.1M ops/sec
Throws: Error if not exactly 16 bytes
extractTimestamp(uuid)
Extract timestamp from UUID v7 as Date object.
import { extractTimestamp } from "@lpm.dev/neo.uuid";
const id = uuidv7();
const timestamp = extractTimestamp(id);
// Date (accurate to millisecond)
console.log(timestamp.toISOString());
// '2024-05-15T10:30:45.123Z'Returns: Date | null (null if not v7)
extractTimestampMs(uuid)
Extract timestamp from UUID v7 as milliseconds since Unix epoch.
import { extractTimestampMs } from "@lpm.dev/neo.uuid";
const id = uuidv7();
const ms = extractTimestampMs(id);
// 1715771445123
console.log(new Date(ms));
// Date (accurate to millisecond)Performance: 1.1M ops/sec
Returns: number | null (null if not v7)
Constants
import {
NIL, // '00000000-0000-0000-0000-000000000000'
MAX, // 'ffffffff-ffff-ffff-ffff-ffffffffffff'
NAMESPACE_DNS, // '6ba7b810-9dad-11d1-80b4-00c04fd430c8'
NAMESPACE_URL, // '6ba7b811-9dad-11d1-80b4-00c04fd430c8'
NAMESPACE_OID, // '6ba7b812-9dad-11d1-80b4-00c04fd430c8'
NAMESPACE_X500, // '6ba7b814-9dad-11d1-80b4-00c04fd430c8'
} from "@lpm.dev/neo.uuid";Tree-Shaking Examples
Import only what you need for minimal bundle size:
// v4 only: ~0.1 KB
import { uuidv4 } from '@lpm.dev/neo.uuid'
// v4 + v7: ~1.1 KB
import { uuidv4, uuidv7 } from '@lpm.dev/neo.uuid'
// v4 + v7 + validation: ~1.5 KB
import { uuidv4, uuidv7, validate, version } from '@lpm.dev/neo.uuid'
// All features: ~5.7 KB
import * from '@lpm.dev/neo.uuid'Performance Benchmarks
Benchmarked on Node.js v18+ (Vitest bench, 2024 MacBook):
Generation
| Operation | neo.uuid | uuid package | nanoid | Winner |
|---|---|---|---|---|
| UUID v4 | 10.1M ops/s | 6.4M ops/s | 5.3M ops/s | ⚡️ neo.uuid (1.57x faster) |
| UUID v7 | 878K ops/s | 5.1M ops/s | N/A | uuid package (5.79x faster) |
| UUID v5 | 71K ops/s (async) | 537K ops/s (sync) | N/A | uuid package (7.53x faster) |
| 1000 v4 UUIDs | 14.9K ops/s | 8.5K ops/s | 6.7K ops/s | ⚡️ neo.uuid (1.76x faster) |
Validation
| Operation | neo.uuid | uuid package | Winner |
|---|---|---|---|
| Format validation (v4) | 9.4M ops/s | 9.7M ops/s | Tie (~3% difference) |
| Version detection (v4) | 8.1M ops/s | 5.8M ops/s | ⚡️ neo.uuid (1.40x faster) |
| Invalid UUID | 15.5M ops/s | 24.9M ops/s | uuid package (1.60x faster) |
Parsing
| Operation | neo.uuid | uuid package | Winner |
|---|---|---|---|
| Parse (string → bytes) | 1.3M ops/s | 2.9M ops/s | uuid package (2.26x faster) |
| Stringify (bytes → string) | 1.1M ops/s | 1.6M ops/s | uuid package (1.48x faster) |
| Roundtrip (parse + stringify) | 597K ops/s | 1.6M ops/s | uuid package (2.69x faster) |
| Timestamp extraction (v7) | 1.1M ops/s | N/A | ⚡️ neo.uuid (unique feature) |
Summary:
- ⚡️ v4 generation: neo.uuid is 1.57x faster (uses native crypto.randomUUID)
- ⚠️ v7 generation: uuid package is 5.79x faster (more optimized implementation)
- ✅ Validation: Competitive performance (within 3% for format validation)
- ⚡️ Version detection: neo.uuid is 1.40x faster
- ⚠️ Parsing: uuid package is 1.48-2.69x faster
- 🎯 Timestamp extraction: neo.uuid exclusive feature
Bundle Size Analysis
| Import | Size | Use Case |
|---|---|---|
uuidv4() only |
~0.1 KB | Simple random UUIDs |
uuidv4() + uuidv7() |
~1.1 KB | Random + time-ordered UUIDs |
+ validate() + version() |
~1.5 KB | Add validation |
+ parse() + stringify() |
~2.5 KB | Add binary conversion |
| All features | ~5.7 KB | Complete UUID toolkit |
Comparison:
- vs uuid package (v4 only): ~0.1 KB vs ~0.4 KB (4x smaller)
- vs uuid package (all): ~5.7 KB vs ~6-7 KB (up to 20% smaller)
- vs nanoid: ~0.1 KB vs ~0.1 KB (same for v4 only)
TypeScript Support
Written in TypeScript with strict mode enabled:
import type { UUIDVersion, V7Options } from "@lpm.dev/neo.uuid";
// Full type inference
const id: string = uuidv4();
// Version-specific validation
const v: UUIDVersion | null = version(id);
// Optional parameters with types
const customV7: string = uuidv7({ timestamp: Date.now() });TypeScript Config:
strict: trueexactOptionalPropertyTypes: truenoUncheckedIndexedAccess: true- Full type coverage with no
anytypes
UUID v7 Deep Dive
Why UUID v7?
UUID v7 is the modern standard for time-ordered UUIDs (RFC 9562, May 2024):
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms (48 bits) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ver | rand_a (12 bits) |var| rand_b (62 bits) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+Benefits:
- Sortable: UUIDs are lexicographically ordered by creation time
- Database performance: Reduces index fragmentation (B-tree friendly)
- Time-embedded: Extract millisecond-accurate timestamp
- Collision-resistant: 74 bits of randomness (12-bit randa + 62-bit randb)
- Monotonic: Within same millisecond, UUIDs are strictly ordered
Monotonicity Guarantee
neo.uuid implements monotonic counter as recommended by RFC 9562:
const timestamp = Date.now();
// Generate 100 UUIDs in same millisecond
const uuids = Array.from({ length: 100 }, () => uuidv7({ timestamp }));
// All UUIDs are strictly ordered
uuids.every((uuid, i) => i === 0 || uuid > uuids[i - 1]!); // trueHow it works:
- New millisecond → generate fresh random bytes
- Same millisecond → increment counter in rand_b (62 bits)
- Clock rollback → generate fresh random bytes
Database Indexing
UUID v7 significantly improves database performance:
// PostgreSQL example
CREATE TABLE events (
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
created_at TIMESTAMP DEFAULT NOW(),
...
);
// Index-friendly inserts (ascending order)
// Reduces page splits and fragmentationPerformance benefits:
- PostgreSQL 18+: Native UUID v7 support
- MySQL/MariaDB: Better B-tree index performance
- MongoDB: ObjectId-like behavior with timestamps
Compatibility
- Node.js: 18.0.0+ (requires
crypto.randomUUID()) -
Browsers: Modern browsers with Web Crypto API
- Chrome 92+
- Firefox 95+
- Safari 15.4+
- Edge 92+
- Runtimes: Deno, Bun, Cloudflare Workers
Migration Guide
From uuid package
// Before (uuid package)
import { v4 as uuidv4, v7 as uuidv7, validate, version } from "uuid";
// After (neo.uuid)
import { uuidv4, uuidv7, validate, version } from "@lpm.dev/neo.uuid";Changes:
- ✅ Drop-in replacement for v4, v7 generation
- ✅ Compatible
validate()andversion()functions - ⚠️ v5 is async by default (
uuidv5()returns Promise, useuuidv5Sync()for sync) - ⚠️ v1, v3, v6, v8 not supported (use uuid package if needed)
From nanoid
// Before (nanoid)
import { nanoid } from "nanoid";
const id = nanoid(); // '2Rt5YvB3jK9xF5mN8qP1w'
// After (neo.uuid)
import { uuidv4 } from "@lpm.dev/neo.uuid";
const id = uuidv4(); // '550e8400-e29b-41d4-a716-446655440000'Trade-offs:
- ✅ RFC-compliant UUIDs (36 chars vs 21 chars)
- ✅ Multiple versions (v4, v7, v5)
- ✅ Validation and parsing utilities
- ⚠️ Larger bundle (~5.7 KB vs ~0.1 KB for all features)
- ✅ But tree-shakeable (v4 only = ~0.1 KB, same as nanoid)
FAQ
Should I use UUID v4 or v7?
Use UUID v7 if:
- You need sortable IDs (e.g., event logs, audit trails)
- Database performance matters (reduces index fragmentation)
- You want embedded timestamps
- Building new systems (v7 is the modern standard)
Use UUID v4 if:
- Maximum randomness required (122 vs 74 bits)
- No need for time ordering
- Compatibility with existing v4-only systems
- Slightly better performance (10.1M vs 878K ops/sec)
Why is v7 generation slower than uuid package?
Our v7 implementation prioritizes:
- Correctness: Full RFC 9562 compliance with monotonic counter
- Module state isolation: Safe state management
- Code clarity: Maintainable implementation
The uuid package's v7 is highly optimized but more complex. For most applications, 878K ops/sec is more than sufficient.
Is UUID v5 async or sync?
uuidv5(): Async (uses Web Crypto API, works in browsers and Node.js)uuidv5Sync(): Sync (uses Node.js crypto module, Node.js only)
We default to async for cross-platform compatibility. Use uuidv5Sync() if you need synchronous operation in Node.js.
Can I use this in browsers?
Yes! neo.uuid works in all modern browsers with Web Crypto API support:
- Chrome 92+, Firefox 95+, Safari 15.4+, Edge 92+
- Use
uuidv4(),uuidv7(),uuidv5()(async), and all validation/parsing functions
What about v1, v3, v6, v8?
We intentionally exclude legacy/niche versions:
- v1: Exposes MAC addresses (security risk), deprecated
- v3: Uses weak MD5 hash, deprecated
- v6: Reordered v1 timestamp (niche, low adoption)
- v8: Experimental, vendor-specific
Use the uuid package if you need these versions.
License
MIT
Taxes calculated at checkout based on your location.