ULID vs UUID: which should you use?
May 14, 2026 · 17 min read
ULID (Universally Unique Lexicographically Sortable Identifier) and UUID both solve "unique ID in distributed systems," but they optimize for different ergonomics. After UUID v7 landed in standards, the choice is subtler than it was in 2018.
What ULID looks like
A ULID is 128 bits like a UUID, but the canonical string is 26 characters of Crockford Base32
(e.g. 01ARZ3NDEKTSV4RRFFQ69G5FAV). First 48 bits are timestamp; remainder is random.
Case-insensitive and URL-safe without hyphens.
UUID v7 closed the sortability gap
Before UUID v7, teams picked ULID specifically for k-sortable primary keys. v7 now embeds a Unix ms timestamp in standard UUID form, which ORMs and databases already understand. If your stack natively supports v7 generators, ULID's encoding advantage may not justify a second ID type.
Side-by-side comparison
| ULID | UUID v4 | UUID v7 | |
|---|---|---|---|
| Sortable | Yes | No | Yes |
| String length | 26 chars | 36 chars | 36 chars |
| Case sensitivity | No | Hex (often case-insensitive compare) | Same |
| DB native type | Rare (store as string/binary) | Common | Growing |
When ULID still wins
- Log-friendly compact IDs in URLs or Kafka keys.
- Systems already standardized on Base32 ULID strings.
- You want sortability but cannot migrate to UUID v7 yet.
When UUID wins
- PostgreSQL
uuidcolumns and drivers expect canonical form. - Interop with third-party APIs that document UUID fields.
- Compliance reviews referencing RFC 4122 / RFC 9562.
// Pseudocode: both are 128-bit; encoding differs
const ulid = "01ARZ3NDEKTSV4RRFFQ69G5FAV";
const uuid7 = "01890f5e-8b7a-7b3e-b3e2-9c8f0e12a3b4";
Operations, monitoring, and migrations
If your observability stack already indexes request_id as UUID strings, introducing ULID means new
parsers in dashboards. Standardizing on UUID v7 lets you keep the same regex and validator tooling while gaining
sortability. If you already run ULID in Kafka keys and log aggregation, migrating to v7 is optional until a major
platform upgrade forces consolidation.
Lexicographic sort of ULID strings matches creation order when generated on the same machine clock. UUID v7 offers
similar properties in canonical hex. For cross-region writers, clock skew affects both - always pair sortable IDs
with a trusted created_at column for legal and billing workflows.
Try both formats locally: ULID generator and UUID generator run in your browser with no upload.
Case study: greenfield API in 2026
A typical B2B SaaS starts with PostgreSQL, TypeScript, and OpenAPI. If the team already documents resource IDs as
format: uuid, UUID v7 is the path of least resistance: drivers understand it, BI tools recognize it,
and compliance questionnaires already mention RFC 4122. ULID enters the conversation when product wants shorter
share URLs or when the data team already standardized on 26-character keys in an event bus.
Migration from ULID to v7 is a encoding change, not a business-logic change - both are 128 bits. Plan a backfill
window, dual-write if consumers exist outside your database, and add integration tests that sort by ID and by
created_at to ensure both monotonicity stories hold.
FAQ
- Can I convert ULID to UUID?
- Yes at the bit level with correct timestamp and random field mapping. Use dedicated libraries; do not hand-roll unless you enjoy incidents.
- Which is better for PostgreSQL?
- UUID v7 if your version supports it. ULID as TEXT works but loses native uuid operators.
- Is ULID case-sensitive?
- Crockford Base32 is case-insensitive by design, which reduces log copy-paste errors.
- Can I sort ULIDs in Redis?
- Yes as string keys in lexicographic order. Same idea as v7 UUID strings with time-leading bits.
Related: NanoID vs UUID · UUID versions