Before UUID v7 was standardised in RFC 9562 (May 2024), ULID was the most popular way to get time-sortable, globally unique identifiers in distributed systems. Now that v7 has RFC status and PostgreSQL 18 support, the comparison is worth revisiting.
Side-by-Side Comparison
| Property | UUID v7 | ULID |
|---|---|---|
| Timestamp precision | 48-bit Unix milliseconds | 48-bit Unix milliseconds |
| Random bits | 74 bits | 80 bits |
| Total size | 128 bits | 128 bits |
| String format | 018f-be3a-… (36 chars, hex) | 01ARZ3NDEK… (26 chars, Base32) |
| RFC standard | Yes — RFC 9562 | No |
| DB native type | uuid (PostgreSQL, MySQL 8+) | varchar or binary (custom) |
| PostgreSQL 18 | uuidv7() built-in | Extension required |
| Monotonic counter | Optional (RFC recommends) | Yes — counter per millisecond |
| Case-sensitive | No | Yes (Crockford Base32 is case-insensitive in spec, implementations vary) |
Where ULID Has an Edge
Shorter strings. A ULID’s 26-character Base32 encoding is 28% shorter than a UUID’s 36-character hex string. In APIs that return IDs in JSON, or URLs that embed IDs, shorter strings reduce payload size.
More random bits. ULID uses 80 random bits vs UUID v7’s 74. The practical collision risk at any realistic generation rate is negligible for both, but ULID has a slight theoretical edge.
Human readability. Crockford Base32 avoids ambiguous characters (0 vs O, 1 vs I) and is easier to read aloud or transcribe than a hex UUID string.
Where UUID v7 Has an Edge
RFC standard. UUID v7 is defined by RFC 9562. ULID has no IETF standard — it is a community spec maintained on GitHub. Standards matter for long-lived systems, audits, and cross-vendor compatibility.
Native database type. PostgreSQL’s uuid type, MySQL 8’s UUID functions, and SQL Server’s uniqueidentifier all handle UUID v7 natively. ULID requires storing as varchar(26) or binary(16) with manual encoding/decoding.
PostgreSQL 18. The new uuidv7() built-in function means UUID v7 generation can be pushed entirely to the database layer — no application code required for inserts that go through raw SQL or migrations.
Ecosystem support. The uuid npm package, Python’s standard library, google/uuid for Go, and Hibernate 6.5 all support UUID v7. ULID has per-ecosystem community packages with varying maintenance status.
When to Choose ULID
- Your API exposes identifiers in URLs and shorter strings matter for UX.
- Your stack already uses ULID throughout and the migration cost to UUID v7 is not justified.
- You need IDs in an environment without a
uuidcolumn type (e.g., a legacy varchar column you cannot change).
When to Choose UUID v7
- You are starting a new project in 2026 — use the RFC standard.
- You use PostgreSQL and want the
uuidv7()database function. - You need to interoperate with systems that only accept the standard UUID format.
- Your ORM or framework has built-in UUID v7 support (Hibernate 6.5+, Drizzle ORM, Prisma via prisma-uuid-v7).
Related Resources
- RFC 9562 — UUID v7 specification
- ULID specification on GitHub
- oklog/ulid — ULID implementation for Go
- ulid npm package — ULID for JavaScript/TypeScript
Frequently asked questions
Should I use UUID v7 or ULID for sortable IDs?
In 2026, UUID v7 is the better default. It has RFC standardisation (RFC 9562), native PostgreSQL 18 support, and stores in the existing uuid column type. ULID has no RFC standard and requires custom storage. Choose ULID only if shorter 26-char strings are important for your use case.
Should I use v4 or v7?
Use v7 for database primary keys (time-sortable, index-friendly) and v4 for anything where creation order could leak information, like tokens or share links.
What did RFC 9562 add to the UUID standard?
RFC 9562, published in May 2024, adds UUID v6 (reordered timestamp for sortability), v7 (Unix millisecond timestamp), and v8 (custom layout). It also defines the Max UUID sentinel (all-ones complement of the Nil UUID) and deprecates v1 and v2. The existing format and v3, v4, v5 semantics are unchanged.
What is a ULID?
A ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit identifier with a 48-bit millisecond timestamp and 80 random bits, encoded as a 26-character Crockford Base32 string (e.g. 01ARZ3NDEKTSV4RRFFQ69G5FAV). It was designed to be a sortable, human-readable alternative to UUID v4 before UUID v7 was standardised.
Is UUID v7 better than ULID?
For most use cases in 2026, UUID v7 is the better choice. It is an RFC standard (RFC 9562), natively supported in PostgreSQL 18, and stores in the existing uuid column type without schema changes. ULID requires custom storage (varchar or binary) in most databases and has no RFC standard. ULID's Crockford Base32 encoding is more human-readable but adds implementation complexity.