ULID vs KSUID - Which Identifier Should You Use?

ULID (Universally Unique Lexicographically Sortable Identifier) and KSUID (K-Sortable Unique Identifier) are both popular time-sortable alternatives to UUID. Both formats provide time-ordering for better database performance, but they differ in size (128-bit vs 160-bit), encoding (Crockford Base32 vs Base62) and timestamp precision (millisecond vs second).

Quick recommendation: For RFC standards compliance, prefer GUID / UUID v4 (fully random) or GUID / UUID v7 (time-ordered). If you need a non-RFC alternative, choose ULID for millisecond precision and 128-bit size (same as UUID), or KSUID for more randomness (128 bits) and larger ID space (160-bit).

Universally Unique Lexicographically Sortable Identifier (ULID) - github.com

K-Sortable Unique Identifier (KSUID) - github.com

Overview

ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit identifier using Crockford Base32 encoding (26 characters). It provides millisecond-precision timestamps with 80 bits of randomness. ULID is the same size as standard UUIDs, making it a drop-in replacement for storage purposes.

KSUID (K-Sortable Unique Identifier) is a 160-bit identifier created by Segment, using Base62 encoding (27 characters). It uses second-precision timestamps with 128 bits of randomness, providing a larger ID space than both UUIDs and ULIDs.

Neither format is governed by an RFC standard. Both are non-standard alternatives designed for specific use cases where time-ordering and sortability are priorities.

Comparison table

PropertyULIDKSUID
Size128-bit (16 bytes)160-bit (20 bytes)
EncodingCrockford Base32
26 chars
Base62
27 chars
Time-sortableYes
Millisecond
Yes
Second
Standard Community spec
No RFC
Segment.io spec
No RFC
Human-readableGood
Base32, case-insensitive
Good
Base62, compact
Database-friendlyModerate
No native type (only text/binary), 16 bytes
Moderate
No native type (only text/binary), 20 bytes
Collision resistantExcellent
80 bits random
Excellent
128 bits random
Best forHuman-friendly sortable IDs, URL-safe identifiersLog/event systems, large-scale distributed tracing

Detailed comparison

ULID (Universally Unique Lexicographically Sortable Identifier)

Structure: 128 bits with 48-bit Unix millisecond timestamp + 80 bits randomness, encoded in Crockford Base32.

  • Pros: Millisecond precision, compact Crockford Base32 encoding (26 chars), 128-bit size (same as UUID), lexicographically sortable, no ambiguous characters (0/O, 1/I/L)
  • Cons: Not RFC standard, 80 bits randomness (less than KSUID), requires library support, no native database type
  • Use when: You need time-sortable IDs with millisecond precision and want UUID-compatible storage size

Example: 01ARZ3NDEKTSV4RRFFQ69G5FAV

KSUID (K-Sortable Unique Identifier)

Structure: 160 bits with 32-bit Unix second timestamp + 128 bits randomness, encoded in Base62.

  • Pros: Larger ID space (160 bits), 128 bits of randomness (excellent collision resistance), time-ordered, URL-safe Base62 encoding, second-precision timestamps
  • Cons: Not RFC standard, larger storage than UUIDs/ULIDs (20 bytes vs 16 bytes), requires library support, less universal than UUIDs
  • Use when: You need maximum entropy with time-ordering and second-precision is sufficient

Example: 0ujsszwN8NRY24YaXiTIE2VWDTS

Which one should you use?

  • Choose ULID if you need millisecond-precision timestamps, want 128-bit size (same storage as UUID), prefer Crockford Base32 encoding (no ambiguous characters), or need lexicographically sortable IDs.
  • Choose KSUID if you need a larger ID space (160 bits), require more randomness (128 bits vs 80 bits), second-precision timestamps are sufficient, or your infrastructure already uses KSUID.
  • Consider GUID / UUID v7 if RFC standards compliance matters to you. It offers time-ordering with millisecond precision while being a real UUID with broad ecosystem support.

Practical guidance for databases

Both ULID and KSUID are time-ordered identifiers that improve database performance compared to random IDs. When records are inserted in approximate time order, B-tree indexes experience fewer page splits and better cache locality.

  • Storage size: ULID uses 16 bytes (same as UUID), while KSUID uses 20 bytes. At scale, this 25% difference can add up significantly.
  • Index fragmentation: Both formats reduce fragmentation compared to random UUIDs since records are inserted in approximate time order.
  • Native type support: Neither ULID nor KSUID has native database type support. Both must be stored as strings or binary blobs.

Performance considerations

  • B-tree indexes: Both ULID and KSUID reduce page splits and improve insert performance in databases using B-tree indexes (PostgreSQL, MySQL, etc.).
  • Storage overhead: ULIDs are 128 bits (16 bytes), KSUIDs are 160 bits (20 bytes). Consider this difference when choosing at scale.
  • Timestamp precision: ULIDs provide millisecond ordering, KSUIDs provide second ordering. IDs created within the same second/millisecond are ordered by their random component.

Interoperability and ecosystem support

Both ULID and KSUID are non-RFC formats that require library support. Neither has the universal ecosystem support that standard UUIDs enjoy.

ULID ecosystem:

  • Broader adoption than KSUID in many ecosystems (JavaScript, Go, Rust, Python)
  • 128-bit size allows storage in UUID-sized database columns (as binary)
  • Crockford Base32 encoding is case-insensitive and avoids ambiguous characters
  • Must be stored as strings or binary in databases (no native ULID type)

KSUID ecosystem:

  • Originally developed by Segment, well-supported in Go ecosystem
  • Requires custom handling in most databases and ORMs
  • Must be stored as strings (27 chars) or binary (20 bytes)
  • May need custom converters for serialization frameworks

Other identifier formats

Beyond ULID and KSUID, there are many other identifier formats each with their own trade-offs. For a comprehensive comparison of all popular identifier formats, see our complete identifier comparison guide.

For applications requiring broad compatibility and standards compliance, standard GUIDs / UUIDs (particularly GUID / UUID v7) remain an excellent choice that combines time-ordering with RFC compliance.

Warnings and trade-offs

  • Identifiers are not secrets: Both ULID and KSUID are identifiers, not security tokens. Do not use them as access tokens or authentication secrets.
  • Time leakage: Both ULID and KSUID embed timestamps that reveal approximate creation time. If timestamp privacy matters, consider GUID / UUID v4 instead.
  • Non-standard formats: Neither ULID nor KSUID is an RFC standard. Some APIs, ORMs, and databases assume UUID formatting and won't accept them without custom handling.
  • Collision risk differences: ULID has 80 bits of randomness while KSUID has 128 bits. At extremely high generation rates, ULID has higher collision probability.
  • Sorting depends on representation: "Time-sortable" usually means the string form sorts by time, but database storage/byte-order can change behavior.
  • Migration complexity: Switching from one identifier format to another in an existing system can be challenging and may require data migration.

Frequently Asked Questions

No. While both are time-sortable alternatives to UUID, they differ significantly: ULID is 128-bit with Crockford Base32 encoding (26 chars) and millisecond timestamp precision, while KSUID is 160-bit with Base62 encoding (27 chars) and second timestamp precision. ULID has 80 bits of randomness vs KSUID's 128 bits.

KSUID uses 128 bits of randomness compared to ULID's 80 bits. Combined with the 32-bit timestamp, this results in 160 bits total. The extra randomness provides higher collision resistance for extremely high-volume systems, though ULID's 80 bits is sufficient for most applications.

Both work well as primary keys since they're time-ordered. ULID is preferred when storage size matters (16 bytes vs 20 bytes) and millisecond precision is needed. KSUID is better when you need maximum collision resistance. For standards compliance, consider GUID / UUID v7 which offers similar benefits with RFC support.

No. ULID is 128 bits while KSUID is 160 bits, and their internal structures are completely different (different timestamp precision, different randomness bits, different encoding). You cannot meaningfully convert between them. Choose one format for your system and stick with it.

Both are designed for human-readability. ULID uses Crockford Base32 which avoids ambiguous characters (0/O, 1/I/L): 01ARZ3NDEKTSV4RRFFQ69G5FAV. KSUID uses Base62 (alphanumeric only): 0ujsszwN8NRY24YaXiTIE2VWDTS. Both are more readable than hex-encoded UUIDs.

ULID has slightly higher collision risk due to 80 bits of randomness vs KSUID's 128 bits. However, 80 bits is still sufficient for most practical applications. At extremely high generation rates (millions per millisecond), KSUID's extra randomness provides better protection. Both require cryptographically secure random number generation.

Neither directly. PostgreSQL's uuid type is exactly 128 bits with specific hex formatting. ULID (128-bit but Base32) must be stored as text (26 chars) or bytea (16 bytes). KSUID (160-bit) must be stored as text (27 chars) or bytea (20 bytes). For native PostgreSQL UUID support, use standard GUIDs / UUIDs.

Both work well for logging. Choose ULID if you need millisecond-precision timestamps for fine-grained event ordering. Choose KSUID if second-precision is sufficient and you want maximum entropy. For standards compliance with time-ordering, consider UUID v7.

Choose KSUID when: (1) you need maximum collision resistance (128 bits vs 80 bits random), (2) second-precision timestamps are sufficient, (3) your infrastructure already uses KSUID (especially Go ecosystems), or (4) the extra 4 bytes of storage isn't a concern. Choose ULID for millisecond precision, smaller storage, or Crockford Base32 encoding preferences.

Conclusion

Choose ULID when you need millisecond-precision timestamps, prefer the same 128-bit storage size as UUIDs, want Crockford Base32 encoding (no ambiguous characters), or need lexicographically sortable identifiers with compact representation.

Choose KSUID when you need maximum collision resistance (128 bits of randomness), second-precision is sufficient for your use case, or your infrastructure already uses KSUID (common in Go ecosystems).

For RFC standards compliance with time-ordering benefits, consider GUID / UUID v7 as an alternative that provides millisecond precision with broad ecosystem support.

By using this site, you agree to our Privacy Policy and Terms of Service. You are not permitted to use the GUIDs / UUIDs generated by this site or use any other content, services and information available if you do not agree to these terms.
Disclaimer: All information is provided for general educational and technical reference only. While we aim to keep the content accurate, current and aligned with published standards, no guarantees are made regarding completeness, correctness or suitability for any specific use case.
GUID / UUID specifications, best practices, security guidance, database behavior and ecosystem conventions (including cloud platforms and identifier formats) may change over time or differ by implementation. Examples, recommendations and comparisons are illustrative and may not apply universally.
This content should not be considered legal, security, compliance or architectural advice. Before making critical design, security or production decisions, always consult the latest official standards and vendor-specific documentation.
Always evaluate behavior in your own environment.
Standards Compliance: The GUIDs / UUIDs generated by this site conform to RFC 4122 and RFC 9562 specifications whenever possible, using cryptographically secure random number generation.