Every database row, every API resource, every distributed event needs an ID. The problem isn’t generating one — it’s choosing the format that won’t bite you six months in when your Postgres indexes are fragmented and your URLs look like noise.
Here’s the full uuid generator comparison: UUID v4, UUID v7, ULID, CUID2, and Snowflake — what they are, where they break down, and which one you should actually use.
UUID v4: The Safe Default (With One Big Problem)
UUID v4 is 128 bits of randomness, formatted as 550e8400-e29b-41d4-a716-446655440000. It’s universally understood, supported in every language, every database, and every ORM on the planet.
The collision probability is effectively zero — you’d need to generate a billion UUIDs per second for 85 years before hitting a 50% chance of a single collision. That’s not a concern in practice.
The problem is ordering. UUID v4 is completely random, which means inserting rows into a UUID-indexed table scatters writes across the B-tree. At scale, this causes page splits, index fragmentation, and degraded insert performance. If you’re inserting thousands of rows per second into a MySQL or Postgres table with a UUID primary key, you will feel this.
UUID v4 is also 36 characters as a string — not URL-safe without encoding, and bloated compared to alternatives.
UUID v7: UUID v4’s Better Sibling
UUID v7 fixes the ordering problem. It’s a time-ordered UUID where the most significant bits encode a millisecond timestamp, and the rest is random. The result: 01875f3a-7b2d-7f8e-a3d1-4b2e6c1a0f93.
Rows inserted in time order stay roughly sequential in the index. That’s a significant win for write-heavy workloads. UUID v7 is compatible with all existing UUID infrastructure — same format, same field length, same library support expectations — while adding sortability.
The RFC was finalized in 2022 and library support is catching up fast. If you’re already using UUIDs and can’t change your schema, switching from v4 to v7 is low-risk and high-reward.
ULID: The Most Developer-Friendly Option
ULID (Universally Unique Lexicographically Sortable Identifier) encodes a 48-bit timestamp and 80 bits of randomness into 26 Base32 characters: 01ARZ3NDEKTSV4RRFFQ69G5FAV.
What makes it stand out:
- Sortable by default — lexicographic sort is chronological sort
- URL-safe — no hyphens, no special characters
- Case-insensitive — avoids the
0/Oand1/Iambiguity by excluding those characters from the alphabet - Compact — 26 characters vs 36 for a UUID string
ULID is the most practical choice for new projects that don’t have legacy constraints. It’s sortable enough for most use cases, short enough for URLs, and readable enough that a human can copy-paste it without making transcription errors.
One caveat: if you generate multiple ULIDs within the same millisecond, the monotonic sort order is guaranteed per-process but not across distributed nodes. For most applications, that’s fine.
CUID2: Built for Distributed Systems
CUID2 is the successor to CUID, redesigned from scratch for security and collision resistance in distributed environments. A CUID2 looks like: clh3uj5ln0000qzrmn831mbhe.
It uses a SHA-3 hash of a combination of timestamp, counter, fingerprint (process ID + hostname), and random bytes. The fingerprint is the key difference — it’s designed specifically to prevent collisions when you’re running many ID generators simultaneously across many servers.
CUID2 is not sortable. It prioritizes collision resistance and unpredictability over time ordering. If you’re building a system where IDs are generated by untrusted clients or across a large number of independent nodes and security is a concern, CUID2 is worth the tradeoff.
For most backend APIs, it’s overkill.
Snowflake IDs: High Throughput, But You’re on Your Own
Snowflake IDs were invented at Twitter for generating unique IDs at millions per second across a distributed cluster. A Snowflake ID is a 64-bit integer: timestamp (41 bits) + datacenter ID (5 bits) + machine ID (5 bits) + sequence (12 bits).
They’re sortable, compact (fits in a BIGINT), and extremely fast. Discord, Instagram, and many high-scale systems use this pattern.
The catch: you need to manage machine IDs. That means a coordination service (ZooKeeper, etcd, a database table) to assign unique machine IDs to each ID generator. If two nodes share a machine ID, you get collisions. Setting that up correctly is non-trivial, and maintaining it is operational overhead.
Unless you’re generating hundreds of thousands of IDs per second, the complexity isn’t worth it.
The Comparison
| UUID v4 | UUID v7 | ULID | CUID2 | Snowflake | |
|---|---|---|---|---|---|
| Sortable | No | Yes | Yes | No | Yes |
| URL-safe | No (hyphens) | No (hyphens) | Yes | Yes | Yes (integer) |
| Collision resistance | Very high | Very high | High | Very high | High (w/ coordination) |
| Complexity | None | None | None | Low | High |
| Typical use case | Legacy systems, general use | DB primary keys | APIs, URLs, new projects | Distributed/untrusted clients | High-throughput systems |
Generating Each in Node.js
// UUID v4
import { v4 as uuidv4 } from 'uuid';
console.log(uuidv4()); // '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'
// UUID v7
import { v7 as uuidv7 } from 'uuid';
console.log(uuidv7()); // '01875f3a-7b2d-7000-8000-4b2e6c1a0f93'
// ULID
import { ulid } from 'ulid';
console.log(ulid()); // '01ARZ3NDEKTSV4RRFFQ69G5FAV'
// CUID2
import { createId } from '@paralleldrive/cuid2';
console.log(createId()); // 'clh3uj5ln0000qzrmn831mbhe'
// Snowflake (using @socialgouv/nextid for simplicity)
import Snowflake from '@socialgouv/nextid';
const snowflake = new Snowflake(1n); // machine ID = 1
console.log(snowflake.nextId().toString()); // '1641024000000000001'
You can test UUID generation directly with the IO Tools UUID Generator — it supports UUID v1 through v7 and bulk generation without installing anything.
Which One Should You Use?
Here’s the actual recommendation, not the cop-out “it depends” version:
- New project, no legacy constraints: Use ULID. Sortable, URL-safe, compact. It’s the best default.
- Already using UUIDs, need better DB performance: Migrate to UUID v7. Drop-in upgrade, massive index win.
- IDs generated by clients or across untrusted distributed nodes: Use CUID2. The fingerprinting makes collision resistance robust even in adversarial conditions.
- High-throughput platform (100k+ IDs/sec), willing to manage machine IDs: Use Snowflake. Otherwise, don’t bother.
- UUID v4: Only if you’re maintaining legacy code and can’t change the format. Stop using it for new tables.
The era of defaulting to UUID v4 for everything is over. ULID is the new default for most use cases, and UUID v7 is the right upgrade path if you’re already in UUID land. Pick one and move on.
Install Our Extensions
Add IO tools to your favorite browser for instant access and faster searching
恵 Scoreboard Has Arrived!
Scoreboard is a fun way to keep track of your games, all data is stored in your browser. More features are coming soon!
Must-Try Tools
View All New Arrivals
View AllUpdate: Our latest tool was added on Apr 19, 2026
