Neo Zero

uuid

Pool

Zero-dependency UUID library - Modern, tree-shakeable alternative to uuid package

$ lpm install @lpm.dev/neo.uuid

@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.uuid

Quick 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 IDs
  • NAMESPACE_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"); // false

Performance: 9.4M ops/sec

Parameters:

  • uuid: string - UUID string to validate
  • version?: 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"); // null

Performance: 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: true
  • exactOptionalPropertyTypes: true
  • noUncheckedIndexedAccess: true
  • Full type coverage with no any types

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:

  1. Sortable: UUIDs are lexicographically ordered by creation time
  2. Database performance: Reduces index fragmentation (B-tree friendly)
  3. Time-embedded: Extract millisecond-accurate timestamp
  4. Collision-resistant: 74 bits of randomness (12-bit randa + 62-bit randb)
  5. 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]!); // true

How 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 fragmentation

Performance 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() and version() functions
  • ⚠️ v5 is async by default (uuidv5() returns Promise, use uuidv5Sync() 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:

  1. Correctness: Full RFC 9562 compliance with monotonic counter
  2. Module state isolation: Safe state management
  3. 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

lpmuuidguidv4v7v5identifierunique-idtime-orderedsortablezero-dependencytree-shakeabletypescript
Unlimited AccessInstall as many Pool packages as you need.
Fund Real WorkEvery install you run sends revenue directly to the developer who built it.

Taxes calculated at checkout based on your location.

Weekly Installs
3
Version
1.0.0
Published
LicenseMIT
Size119.18 KB
Files13
Node version>= 18
TypeScriptYes