Back to Blog Index
Security & Cryptography12 min read

UUIDs, NanoIDs, and Unique Identifier Engineering: Choosing the Right ID Strategy

Compare UUID v4, UUID v7, NanoID, CUID, ULID, and sequential IDs. Understand collision mathematics, database indexing implications, and distributed system ID strategies.

ToolZeno Editorial Team

Software Architecture & Security Guild

Published 2026-07-06 (Updated 2026-07-30)
#UUID#NanoID#Identifiers#Database#Distributed Systems#Architecture

Why Unique Identifier Strategy Matters in Software Architecture

Every record in a database, every event in a log stream, every message in a queue, and every entity in a distributed system needs a unique identifier. The choice of identifier format has far-reaching implications for database performance, system security, horizontal scalability, and API design.

Auto-incrementing integers (1, 2, 3...) are the simplest approach but expose several problems at scale. They leak business intelligence (competitors can estimate your total user count or order volume by observing sequential IDs), they create single-point-of-failure bottlenecks in distributed databases (which node assigns the next number?), and they enable enumeration attacks where attackers systematically access resources by incrementing IDs.

Random identifiers like UUIDs solve the enumeration and distribution problems but introduce their own challenges: they are larger (128 bits vs 32/64 bits), they fragment B-tree database indexes when inserted randomly (degrading write performance), and their text representations are long and unwieldy in URLs and logs.

Modern identifier formats like UUID v7, ULID, and NanoID represent different tradeoffs in this design space. Understanding these tradeoffs enables engineers to select the optimal identifier strategy for each specific use case rather than defaulting to a single approach.

UUID Collision Probability

A UUID v4 has 122 random bits, providing 5.3 × 10^36 possible values. You would need to generate approximately 2.71 × 10^18 (2.71 quintillion) UUIDs before having a 50% probability of a single collision. In practical terms, collisions are impossible.

UUID Versions Explained: v1, v4, v5, and v7

The UUID (Universally Unique Identifier) standard defined in RFC 9562 specifies several versions, each using different generation strategies.

UUID v1 combines a 60-bit timestamp (100-nanosecond intervals since October 15, 1582) with the network MAC address of the generating machine. This produces time-sortable IDs but exposes hardware identifiers and approximate generation times, creating privacy concerns. UUID v1 is rarely recommended for new applications.

UUID v4 generates 122 bits of cryptographic randomness (using crypto.getRandomValues in browsers or crypto.randomUUID()). This is the most widely used version because it requires no coordination between generating nodes, exposes no metadata, and is trivially simple to implement. The tradeoff is that random UUIDs fragment B-tree indexes in databases like PostgreSQL, MySQL, and SQLite, degrading insert performance by 20-40% compared to sequential inserts.

UUID v5 generates deterministic, namespace-based identifiers by hashing a namespace UUID and a name string using SHA-1. Given the same namespace and name, UUID v5 always produces the same output. This is valuable for generating stable identifiers from natural keys (e.g., generating a consistent UUID from a username or email address).

UUID v7 (RFC 9562, 2024) is the newest version and the recommended choice for new database-backed applications. It combines a 48-bit Unix timestamp (millisecond precision) with 74 bits of randomness. The timestamp prefix makes UUIDs roughly chronologically sortable, preserving B-tree locality and maintaining near-sequential insert performance while retaining the distributed generation and unpredictability benefits of random IDs.

Format comparison of common identifier strategies.

// Format examples for each UUID version:

// UUID v4 (random): no timestamp, pure randomness
// 550e8400-e29b-41d4-a716-446655440000

// UUID v7 (timestamp + random): chronologically sortable
// 018f3b3c-8e1a-7b2c-9d4e-5f6a7b8c9d0e
// └── timestamp ──┘ └─── random ───┘

// NanoID (21 chars, URL-safe): compact alternative
// V1StGXR8_Z5jdHi6B-myT

// ULID (26 chars, Crockford Base32): sortable + compact
// 01ARZ3NDEKTSV4RRFFQ69G5FAV

NanoID, ULID, CUID: Modern UUID Alternatives

Several modern alternatives address specific UUID limitations while maintaining uniqueness guarantees.

NanoID generates compact, URL-safe identifiers using a customisable alphabet. The default configuration produces 21-character strings using A-Za-z0-9_- (64 characters), providing 126 bits of entropy — comparable to UUID v4's 122 bits but in a string that is 15 characters shorter. NanoID uses crypto.getRandomValues for cryptographic security and is available in every major programming language. Its compact size makes it ideal for URL slugs, short codes, and systems where storage or bandwidth is constrained.

ULID (Universally Unique Lexicographically Sortable Identifier) combines a 48-bit millisecond timestamp with 80 bits of randomness, encoded in Crockford's Base32 format. The result is a 26-character string that is chronologically sortable (preserving B-tree locality like UUID v7), case-insensitive, and avoids confusing characters (no I, L, O, or U). ULIDs are popular in event sourcing architectures and time-series databases.

CUID2 (Collision-resistant Unique Identifier, version 2) generates secure, compact identifiers with built-in collision resistance. It uses a combination of timestamp, counter, fingerprint, and randomness, producing identifiers that are horizontally scalable without coordination. CUID2 was designed specifically for web applications and is optimised for distributed systems.

The choice between these formats depends on your specific requirements: UUID v7 for database primary keys (best B-tree performance), NanoID for URL-facing identifiers (compact and URL-safe), ULID for event logs and time-series data (sortable and readable), and auto-increment for internal counters where ordering matters more than security.

  • UUID v7 is the best choice for new database primary keys — sortable, random, and RFC-standardised.
  • NanoID is ideal for URL slugs, API keys, and user-facing identifiers — compact and URL-safe.
  • ULID is perfect for event sourcing and time-series data — sortable and case-insensitive.
  • Never use auto-increment IDs for user-facing APIs — they enable enumeration attacks and leak business data.
  • Always use cryptographic random sources (crypto.getRandomValues) rather than Math.random() for ID generation.

Generating Secure Identifiers in the Browser

Modern browsers provide the crypto.randomUUID() API that generates RFC-compliant UUID v4 identifiers using the operating system's cryptographic entropy pool. This API is available in all modern browsers (Chrome 92+, Firefox 95+, Safari 15.4+) and Node.js 19+.

For NanoID and custom-alphabet identifiers, the Web Crypto API's crypto.getRandomValues() method fills a typed array with cryptographic random values. This is the same entropy source used by server-side key generation and is considered suitable for cryptographic purposes. Math.random() should never be used for identifier generation because it uses a pseudo-random number generator (PRNG) that may produce predictable sequences.

Client-side ID generation is valuable for several scenarios: creating unique keys for React list rendering without server round-trips, generating idempotency keys for API requests, pre-assigning resource IDs before submitting creation requests (enabling optimistic UI updates), and creating temporary identifiers for drag-and-drop or clipboard operations.

ToolZeno's UUID Generator and NanoID Generator use crypto.getRandomValues() to produce identifiers entirely in your browser. The generated IDs never pass through any server infrastructure, ensuring they cannot be predicted, logged, or correlated with your identity by external systems.

Frequently Asked Questions

Q:Can UUID v4 identifiers ever collide?

Theoretically yes, but practically no. UUID v4 has 122 bits of randomness, providing 5.3 × 10^36 possible values. You would need to generate 2.71 quintillion UUIDs for a 50% collision probability. For comparison, the entire internet generates fewer than 10 billion UUIDs per day.

Q:Why do random UUIDs degrade database performance?

Random UUIDs cause B-tree index fragmentation because new inserts land at random positions in the index, triggering frequent page splits and random I/O. UUID v7 solves this by prepending a timestamp, making inserts roughly sequential.

Q:Should I use UUIDs or auto-increment integers for database primary keys?

Use UUID v7 for any data exposed through APIs or distributed across multiple databases. Use auto-increment integers only for internal tables that never face the public internet and don't need to be generated without database coordination.

Q:What is the difference between NanoID and UUID?

UUID v4 is 36 characters (including hyphens), RFC-standardised, and universally recognised. NanoID is 21 characters (40% shorter), URL-safe by default, and uses a customisable alphabet. Both provide comparable collision resistance (~122-126 bits of entropy).

Explore More Technical Guides

Design & Accessibility

Understanding Web Accessibility & WCAG 2.1 Contrast Ratios for Modern Web Apps

A comprehensive developer's masterclass on WCAG 2.1 AA/AAA color contrast standards, relative luminance math, color blindness vision deficiencies, and building accessible UI design systems.

12 min readRead
Security & Cryptography

JSON Web Tokens (JWT) Deep-Dive: Architecture, Security Standards, and Local Debugging

An in-depth security engineering guide to RFC 7519 JWT structure, digital signatures (HS256 vs RS256), token vulnerability vectors, and safe client-side debugging.

14 min readRead
Performance & Optimization

Image Optimization Strategies for Core Web Vitals: WebP, SVG, and Compression Techniques

Master image compression algorithms, next-generation WebP/AVIF file formats, SVG vector minification, and responsive image loading to achieve 100 Lighthouse performance scores.

12 min readRead
Security & Cryptography

Understanding Password Entropy, Key Derivation, and Cryptographic Hash Functions

Explore the mathematics of password entropy, NIST 800-63B security standards, salt iterations, and SHA-256 vs Argon2 key derivation functions for modern authentication systems.

13 min readRead
Developer Workflows

The Developer's Guide to Cron Expressions, Syntax Parsing, and Execution Schedules

Learn standard 5-field cron syntax, special wildcards, Quartz scheduler differences, common scheduling patterns, and how to validate background cron jobs accurately.

11 min readRead
Developer Workflows

JSON Formatting & Validation in High-Performance Web Applications

Discover best practices for parsing multi-megabyte JSON payloads, handling circular object references, schema validation, Web Worker parsing, and safe browser-based formatting.

12 min readRead
Developer Workflows

Base64 Encoding & Decoding: How It Works, When to Use It, and Common Pitfalls

A thorough technical guide to the Base64 encoding algorithm, its mathematical foundations, practical use cases in web development, and critical security misunderstandings.

11 min readRead
Developer Workflows

Regular Expressions Mastery: Pattern Syntax, Performance Traps, and Real-World Recipes

Master regex pattern syntax from fundamentals to advanced lookaheads, understand catastrophic backtracking, and learn production-tested patterns for email, URL, and data validation.

14 min readRead