UUID, ULID, or NanoID? Choosing the right ID format for your project
There are at least five different "universal" ID formats in common use today. If you've ever stared at a database schema and wondered why the primary key column is a UUID when the app next door uses a ULID, or why some APIs hand back 21-character strings that look like scrambled alphabet soup — this guide is for you.
We'll cover what each format is, when to use it, and why generating them in your browser (rather than on a server) is safe.
The short version
| Format | Length | Sortable? | Deterministic? | Best for | |--------|--------|-----------|----------------|----------| | UUID v4 | 36 chars | No | No | General-purpose random IDs | | UUID v1 | 36 chars | Yes (by time) | No | Time-ordered records | | UUID v5 | 36 chars | No | Yes | Content addressing, stable IDs | | ULID | 26 chars | Yes | No | Database primary keys | | NanoID | 21 chars (default) | No | No | URL slugs, compact IDs |
UUID v4: the sensible default
UUID v4 is 128 bits of cryptographically random data, formatted as five hyphen-separated groups of hexadecimal digits: 550e8400-e29b-41d4-a716-446655440000.
The v4 designation means version 4, which tells any UUID-aware system that this identifier was generated randomly (as opposed to v1, which is timestamp-based, or v5, which is a hash). The two bits in the variant field confirm it follows the RFC 4122 standard.
When to use v4:
- Database primary keys when insertion order doesn't matter
- Session tokens and correlation IDs
- Anywhere you need a unique ID and have no other constraints
When NOT to use v4:
- When you need IDs to sort chronologically (use ULID or v1 instead)
- When you need to regenerate the same ID from the same input (use v5 instead)
- In URLs where shortness matters (use NanoID instead)
UUID v1: timestamp-based ordering
UUID v1 embeds a 60-bit timestamp (100-nanosecond intervals since 15 October 1582), a clock sequence, and a node identifier. The result looks identical to v4 but sorts chronologically when lexicographically compared.
In desktop applications, the node component was historically the MAC address of the network interface — which raised privacy concerns. In browsers, this field is randomised, so no hardware information leaks.
When to use v1:
- Event logs where you want natural time ordering
- Distributed systems where you need IDs to be roughly sortable across nodes without coordination
Caveat: UUID v1 ordering breaks down when two events occur within the same 100-nanosecond window, or when system clocks drift. For stricter guarantees, use ULID.
UUID v5: deterministic IDs from known inputs
UUID v5 is a SHA-1 hash of a namespace UUID plus a name string. The output is always the same for the same inputs — which is precisely the point.
uuidv5('6ba7b810-9dad-11d1-80b4-00c04fd430c8', 'example.com')
// → '9073926b-929f-31c2-abc9-fad77ae3e8eb' — always
The RFC defines four standard namespaces:
- DNS — for domain names
- URL — for URLs
- OID — for ISO OIDs
- X.500 — for X.500 distinguished names
When to use v5:
- Turning a well-known name into a stable UUID (e.g., product SKU → UUID for a lookup table)
- Content addressing: the UUID of a document is derived from its canonical URL
- Any situation where "same input should always give the same ID" is a requirement
Note: UUID v3 does the same thing with MD5 instead of SHA-1. SHA-1 is stronger; there is no reason to use v3 for new code.
ULID: UUIDs that sort like timestamps
ULID (Universally Unique Lexicographically Sortable Identifier) was created to solve a specific problem: UUID v4's random distribution causes index fragmentation in B-tree database indexes.
When you insert UUIDs in random order, your database index pages fill up partially and need to be split constantly. This degrades write performance as the table grows. Sequential IDs (like auto-incrementing integers or ULIDs) always append to the right end of the index, which is much more efficient.
A ULID looks like this: 01ARZ3NDEKTSV4RRFFQ69G5FAV
The first 10 characters encode a millisecond-precision Unix timestamp. The remaining 16 characters are random. Because the timestamp comes first, ULIDs sort lexicographically in creation order.
When to use ULID:
- Database primary keys in high-write-throughput systems
- Any situation where UUID v4 would work but you also want sort order
- Replacing auto-increment integers when you need distributed ID generation
When NOT to use ULID:
- When you need to interoperate with systems that expect the UUID hex-and-hyphens format (though ULIDs can be converted)
NanoID: compact and URL-safe
NanoID generates strings from a URL-safe alphabet (A–Z, a–z, 0–9, _, -). The default length is 21 characters — at that length it has approximately the same collision probability as UUID v4 (roughly 1 in 10^30 for 1000 IDs per second over 1000 years).
The key advantage over UUID is compactness: 21 characters versus 36, and no hyphens that need URL-encoding.
When to use NanoID:
- URL slugs and short link IDs
- Anything that appears in a URL and should be as short as possible
- When a human might need to type or read the ID (shorter = fewer mistakes)
Configuring length: You can make NanoID shorter (4 characters for very low-volume use, like invite codes) or longer (32 characters for higher collision resistance in high-volume systems). The birthday paradox calculator tells you the precise collision probability for any length.
Is browser-side UUID generation secure?
Yes — with modern browsers and the correct APIs.
Both crypto.randomUUID() (used for UUID v4) and crypto.getRandomValues() (used by ULID and NanoID) draw from the operating system's CSPRNG (Cryptographically Secure Pseudo-Random Number Generator). This is the same entropy source used by OpenSSL, GnuTLS, and your operating system's key generation tools.
The important thing to verify is that the tool you're using doesn't call Math.random(), which is a fast but cryptographically weak PRNG. OffCloud.tools uses crypto.randomUUID() and crypto.getRandomValues() exclusively. You can verify this in your browser's Developer Tools by checking the Source tab — or by reading the source code directly.
Which format should you choose?
Here's a decision tree:
- Do you need the ID to sort by creation time? → Use ULID (better for databases) or UUID v1 (more widely supported)
- Do you need the same ID for the same input every time? → Use UUID v5
- Will the ID appear in a URL? → Use NanoID (shorter, URL-safe, no hyphens)
- Everything else? → Use UUID v4
When in doubt, UUID v4 is the choice that will never surprise you.
Generate any of these formats — entirely in your browser — with the UUID Generator tool. Nothing leaves your device.