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
Snowflake ID for compact storage (64-bit BIGINT) with centralized machine coordination.
Universally Unique Lexicographically Sortable Identifier (ULID) - github.com
Snowflake ID (Twitter) - 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.
Snowflake ID is a 64-bit identifier created by Twitter, represented as a plain integer (up to 19 digits). It uses millisecond-precision timestamps with 10-bit machine ID and 12-bit sequence number, requiring centralized coordination for machine ID assignment.
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
| Property | ULID | Snowflake ID |
|---|
| Size | 128-bit (16 bytes) | 64-bit (8 bytes) |
|---|
| Encoding | Crockford Base32 (26 chars) | Decimal or Hex 19 digits |
|---|
| Time-sortable | Yes (millisecond) | Yes (millisecond) |
|---|
| Standard | Community spec No RFC | Twitter/X spec No RFC |
|---|
| Human-readable | Good Crockford Base32, no ambiguous chars | Excellent Plain number |
|---|
| Database-friendly | Moderate No native type, 16 bytes | Excellent Native BIGINT, 8 bytes |
|---|
| Collision resistant | Good 80 bits random | Depends Needs unique machine IDs |
|---|
| Best for | Systems needing UUID-sized IDs with millisecond precision and sortability | High-throughput systems with centralized coordination and native integer storage |
|---|
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
Snowflake ID (Twitter)
Structure: 64 bits = 1 unused sign bit + 41-bit timestamp (milliseconds) + 10-bit machine/datacenter ID + 12-bit sequence number.
- Pros: Compact storage (8 bytes), native BIGINT in all databases, millisecond precision, very high throughput (4096 IDs/ms/machine), numeric simplicity, excellent indexing performance
- Cons: Requires machine ID coordination, ~69 year epoch limitation, not globally unique without coordination, no RFC standard, collision risk if machine IDs not unique
- Use when: You have infrastructure for machine ID coordination and want compact native integer storage
Example: 1541815603606036480
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 Snowflake ID if you need compact 64-bit IDs, have infrastructure for machine ID coordination, want native BIGINT database storage, or need high throughput per machine (4096 IDs/ms).
- 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 Snowflake ID 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 Snowflake ID uses only 8 bytes (50% smaller!). At scale, this difference is significant.
- Index fragmentation: Both formats reduce fragmentation compared to random UUIDs since records are inserted in approximate time order.
- Native type support: Snowflake ID has excellent native support via BIGINT in all databases. ULID must be stored as strings or binary blobs.
Performance considerations
- B-tree indexes: Both ULID and Snowflake ID reduce page splits. Snowflake's native BIGINT type offers excellent indexing performance in all databases.
- Storage overhead: ULIDs are 128 bits (16 bytes), Snowflake IDs are 64 bits (8 bytes). Snowflake's smaller size provides significant storage savings at scale.
- Timestamp precision: Both provide millisecond ordering. Snowflake IDs within the same millisecond are ordered by their sequence number.
Interoperability and ecosystem support
Both ULID and Snowflake ID are non-RFC formats that require library support. However, Snowflake ID has excellent native database support via BIGINT.
ULID ecosystem:
- Broad adoption 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)
Snowflake ID ecosystem:
- Originally developed by Twitter, widely adopted (Discord, Instagram variants, and many others)
- Native BIGINT support in all databases with excellent indexing
- Simple integer representation, no special encoding needed
- Requires machine ID coordination infrastructure
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 Snowflake ID are identifiers, not security tokens. Do not use them as access tokens or authentication secrets.
- Time leakage: Both ULID and Snowflake ID embed timestamps that reveal approximate creation time. If timestamp privacy matters, consider GUID / UUID v4 instead.
- Machine ID coordination: Snowflake ID requires centralized machine ID assignment. If machine IDs are not unique across your system, you will have collisions.
- Epoch limitation: Snowflake ID has a ~69 year limit from its custom epoch (typically 2010-11-04 for Twitter). Plan for this limitation in long-lived systems.
- Clock dependency: Snowflake ID depends on synchronized clocks. Clock regression can cause issues with ID generation and ordering.
- 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. They are fundamentally different: ULID is 128-bit with Crockford Base32 encoding and can be generated without coordination. Snowflake ID is 64-bit, represented as a plain integer, and requires centralized machine ID coordination to avoid collisions.
Snowflake ID was designed for efficiency at Twitter's scale. Instead of using a large random component like ULID's 80 bits, Snowflake uses machine ID coordination (10 bits) and a sequence number (12 bits) to ensure uniqueness. This allows it to fit in just 64 bits while supporting 4096 IDs per millisecond per machine.
Snowflake ID excels for database primary keys due to native BIGINT support (8 bytes, excellent indexing). Choose
ULID if you need decentralized generation without machine coordination. For standards compliance, consider
GUID / UUID v7 which offers similar benefits with RFC support.
No. ULID is 128 bits while Snowflake ID is 64 bits, and their internal structures are completely different. ULID uses randomness for uniqueness while Snowflake uses machine coordination. You cannot meaningfully convert between them.
Snowflake ID is more human-readable as it's just a plain number: 1541815603606036480. ULID uses Crockford Base32: 01ARZ3NDEKTSV4RRFFQ69G5FAV. While ULID avoids ambiguous characters, Snowflake's simple numeric format is universally understood.
Yes. Snowflake ID requires that each machine/worker has a unique 10-bit machine ID. If two machines share the same ID, collisions will occur. This requires infrastructure for machine ID assignment (e.g., ZooKeeper, configuration management, or cloud metadata). ULID requires no such coordination.
Snowflake ID has excellent PostgreSQL support via native
BIGINT type (8 bytes, optimal indexing).
ULID must be stored as
text (26 chars) or
bytea (16 bytes). For native UUID support, use standard
GUIDs / UUIDs.
Both work well for logging with millisecond precision. Choose
Snowflake ID if you already have machine coordination infrastructure. Choose
ULID for simpler deployment without coordination requirements. For standards compliance, consider
UUID v7.
Choose Snowflake ID when: (1) you have infrastructure for machine ID coordination, (2) you need compact 64-bit storage, (3) you want native BIGINT database support, or (4) you need high throughput (4096 IDs/ms/machine). Choose ULID for decentralized generation, wider ecosystem support, or when you can't coordinate machine IDs.
Conclusion
Choose ULID when you need decentralized ID generation without coordination, prefer 128-bit storage (same as UUIDs), want Crockford Base32 encoding (no ambiguous characters), or need to generate IDs across distributed systems without central management.
Choose Snowflake ID when you need compact 64-bit storage with native BIGINT database support, have infrastructure for machine ID coordination, or need very high throughput (4096 IDs per millisecond per machine).
For RFC standards compliance with time-ordering benefits, consider GUID / UUID v7 as an alternative that provides millisecond precision with broad ecosystem support.