Introduction
UUID v4 generates purely random IDs that scatter across the key space. In a B-tree index (the default for most databases), random inserts cause page splits and index fragmentation, slowing down writes over time. UUID v7 encodes the current Unix timestamp in milliseconds as the first 48 bits, producing chronologically-sorted IDs. This eliminates index fragmentation and makes UUIDs usable as primary keys in high-write systems.
UUID v4 vs v7: Why Time Ordering Matters
UUID v4 generates purely random IDs that scatter across the key space. In a B-tree index (the default for most databases), random inserts cause page splits and index fragmentation, slowing down writes over time. UUID v7 encodes the current Unix timestamp in milliseconds as the first 48 bits, producing chronologically-sorted IDs. This eliminates index fragmentation and makes UUIDs usable as primary keys in high-write systems.
Collision Probabilities in Practice
UUID v4 has 122 random bits. The birthday paradox gives a 50% collision probability after ~2.7 x 10^18 IDs. To reach this, you would need to generate 100 million IDs per second for 873 years. For any practical application, collisions are not a concern. UUID v7 uses 74 random bits (48 bits are timestamp), so collision probability is slightly higher but still negligible for normal use.
When Not to Use UUIDs
For short-lived session tokens, use a crypto library (48-64 random bytes) instead of UUIDs. For user-facing IDs that should be short (like YouTube-style IDs), use NanoID with a custom alphabet and sufficient entropy. For simple single-server applications, auto-increment integers remain the most efficient choice for primary keys.
Frequently Asked Questions
What is the difference between UUID v4 and UUID v7?
UUID v4 generates purely random 128-bit identifiers with no structure, which causes index fragmentation in databases. UUID v7 encodes a Unix timestamp in the first 48 bits followed by random data, producing chronologically sorted IDs that work efficiently with B-tree indexes. Use v7 for database primary keys and v4 for general-purpose identifiers.
Are UUID collisions a real concern?
For UUID v4 with 122 random bits, the birthday paradox gives a 50% collision probability only after approximately 2.7 quintillion IDs. At 100 million IDs per second, you would need 873 years to reach that point. For any practical application, UUID v4 collisions are not a realistic concern. UUID v7 has slightly fewer random bits but remains safe for normal use.
Why are UUIDs better than auto-increment integers for databases?
UUIDs are globally unique, enabling distributed ID generation without coordination between database nodes. They prevent enumeration attacks (guessing sequential IDs), work across microservices, and can be generated client-side before making API calls. The trade-off is larger storage (16 bytes vs 4 bytes for int) and slightly slower index performance for random UUIDs.
Should I store UUIDs with or without hyphens?
Store UUIDs without hyphens (16 bytes as binary) in the database for optimal storage and index performance. Display them with hyphens (36 characters as string) in user interfaces and APIs. Convert between formats at the application layer. This approach saves 20 bytes per row compared to storing the 36-character string format.
What is NanoID and how does it compare to UUID?
NanoID generates shorter identifiers using a customizable alphabet and length. A 21-character NanoID with Base62 alphabet provides similar entropy to a UUID v4 but in a much shorter format. NanoID is ideal for URL shorteners, invitation codes, and user-facing IDs where readability matters. However, it is not time-ordered like UUID v7.
Can I use UUIDs as primary keys in PostgreSQL?
Yes, PostgreSQL has native UUID support via the uuid data type. For UUID v7, use the pg_uuidv7 extension or generate timestamps in your application. Create a B-tree index on the UUID column for efficient lookups. UUID v7 IDs will maintain insert performance similar to auto-increment integers because of their chronological ordering.
When should I use UUID v1 instead of v4 or v7?
UUID v1 encodes the MAC address and timestamp, which can leak hardware information and is rarely used today. UUID v7 provides the same time-ordering benefit without exposing hardware details. Use UUID v7 for new projects. Legacy systems may still encounter v1, but there is no reason to choose it for new development.
How do I generate UUID v7 in my application?
Most modern UUID libraries support v7 generation. In JavaScript, use the uuid package with uuid.v7(). In Python, use the uuid7 function from the uuid6 package. In Java, use the UUID class from the uuid-creator library. Always use cryptographically secure random number generators for the random portion of the UUID.
Conclusion
Choosing the right UUID version and implementation strategy significantly impacts database performance, scalability, and application architecture. UUID v7 solves the index fragmentation problem that plagued UUID v4, making UUIDs viable as primary keys in high-write systems. For most modern applications, UUID v7 offers the best combination of global uniqueness, chronological ordering, and distributed generation without coordination.
Frequently asked questions
What is the difference between UUID v4 and UUID v7?
UUID v4 generates purely random 128-bit identifiers with no structure, which causes index fragmentation in databases. UUID v7 encodes a Unix timestamp in the first 48 bits followed by random data, producing chronologically sorted IDs that work efficiently with B-tree indexes. Use v7 for database primary keys and v4 for general-purpose identifiers.
Are UUID collisions a real concern?
For UUID v4 with 122 random bits, the birthday paradox gives a 50% collision probability only after approximately 2.7 quintillion IDs. At 100 million IDs per second, you would need 873 years to reach that point. For any practical application, UUID v4 collisions are not a realistic concern. UUID v7 has slightly fewer random bits but remains safe for normal use.
Why are UUIDs better than auto-increment integers for databases?
UUIDs are globally unique, enabling distributed ID generation without coordination between database nodes. They prevent enumeration attacks (guessing sequential IDs), work across microservices, and can be generated client-side before making API calls. The trade-off is larger storage (16 bytes vs 4 bytes for int) and slightly slower index performance for random UUIDs.
Should I store UUIDs with or without hyphens?
Store UUIDs without hyphens (16 bytes as binary) in the database for optimal storage and index performance. Display them with hyphens (36 characters as string) in user interfaces and APIs. Convert between formats at the application layer. This approach saves 20 bytes per row compared to storing the 36-character string format.
What is NanoID and how does it compare to UUID?
NanoID generates shorter identifiers using a customizable alphabet and length. A 21-character NanoID with Base62 alphabet provides similar entropy to a UUID v4 but in a much shorter format. NanoID is ideal for URL shorteners, invitation codes, and user-facing IDs where readability matters. However, it is not time-ordered like UUID v7.
Can I use UUIDs as primary keys in PostgreSQL?
Yes, PostgreSQL has native UUID support via the uuid data type. For UUID v7, use the pg_uuidv7 extension or generate timestamps in your application. Create a B-tree index on the UUID column for efficient lookups. UUID v7 IDs will maintain insert performance similar to auto-increment integers because of their chronological ordering.
When should I use UUID v1 instead of v4 or v7?
UUID v1 encodes the MAC address and timestamp, which can leak hardware information and is rarely used today. UUID v7 provides the same time-ordering benefit without exposing hardware details. Use UUID v7 for new projects. Legacy systems may still encounter v1, but there is no reason to choose it for new development.
How do I generate UUID v7 in my application?
Most modern UUID libraries support v7 generation. In JavaScript, use the uuid package with uuid.v7(). In Python, use the uuid7 function from the uuid6 package. In Java, use the UUID class from the uuid-creator library. Always use cryptographically secure random number generators for the random portion of the UUID.