UUID vs Sequential IDs: When to Use What
Choosing between UUID vs sequential ID is one of those decisions that seems trivial at first but shapes your database performance and system architecture for years. The right database ID strategy depends on how you store data, how you distribute it, and how much you care about guessability. This guide breaks down the real trade-offs so you can pick the right tool for the job.
What Is a UUID?
A UUID (Universally Unique Identifier) is a 128-bit label formatted as a 36-character string. A typical version 4 UUID looks like this: f47ac10b-58cc-4372-a567-0e02b2c3d479. It contains 32 hexadecimal digits grouped into five sections, separated by hyphens.
UUID v4 is the most common variant in web development. It generates 122 bits of randomness, which means there are roughly 5.3 undecillion possible values. That number is so large that you could generate a billion UUIDs every second for a century and still not exhaust the space.
There are other versions. UUID v1 embeds a timestamp and the MAC address of the generating machine, which leaks hardware information and creates predictable patterns. UUID v7, the newest standard, combines a Unix timestamp with random bytes. This gives you time-sortability while keeping the randomness high. Most developers reach for v4 or v7 unless they have a specific reason not to.
If you need a quick way to generate valid UUIDs for testing or prototyping, Randify’s UUID Generator creates version 4 identifiers instantly.
Storage and Performance
The first practical difference between UUIDs and sequential IDs is size. A standard auto-incrementing integer takes 4 bytes (or 8 bytes as a BIGINT). A UUID string takes 36 bytes if stored as text, or 16 bytes if stored as a binary BINARY(16) column. That gap matters when your table has hundreds of millions of rows.
Indexes suffer more than raw storage. Databases like PostgreSQL and MySQL build B-tree indexes that work best when new values arrive in sorted order. Sequential IDs append neatly to the end of the index. UUIDs, being random, scatter insertions across the entire B-tree. This causes page splits, fragmentation, and wasted disk space.
In PostgreSQL, a primary key index on a UUID column can grow 30–50% larger than the equivalent index on a BIGINT. Write throughput also drops because the database must read and modify scattered index pages instead of appending to the last one. MySQL’s InnoDB engine, which clusters data by the primary key, experiences even sharper penalties. Random primary keys turn sequential disk writes into random I/O, which is the slowest pattern for traditional spinning disks and still noticeable on SSDs.
Mitigating Index Bloat
You do not have to accept the performance hit blindly. One option is to store UUIDs as binary 16-byte values instead of 36-character strings. This cuts storage in half. Another is to use ordered identifiers like ULID or UUID v7, which keep the time-based prefix and the random suffix. The database still sees randomness, but it is localized to recent time windows, so insertions cluster near the end of the index.
For MySQL specifically, some teams use a composite primary key such as (created_at, uuid) to restore sequential access patterns. The trade-off is slightly more complex queries and the need to handle timestamp collisions.
Collision Probability
People often worry about UUID collisions. In practice, they are a non-issue for UUID v4. The Birthday Problem tells us that collision risk becomes significant when the number of generated values approaches the square root of the total space. For 122 bits of randomness, that square root is about 2.7 quintillion. If you generate a million UUIDs per second, you would need roughly 85 years before the collision probability reaches 50%.
Real-world collisions happen because of bad random number generators, not because the math breaks down. If your server runs out of entropy or uses a weak pseudo-random source, duplicates become possible. Always use a cryptographically secure random source when generating UUIDs in production.
If you want to see how randomness behaves at scale, Randify’s Hash Generator produces fixed-length digests that share the same collision-resistant properties as good UUID generation.
Distributed Systems
Sequential IDs fall apart the moment you have more than one database. If two application servers each insert into their own shard, both will generate overlapping auto-increment values unless you coordinate carefully. That coordination introduces single points of failure and latency.
UUIDs solve this by design. Because they do not rely on a central counter, any node can generate an ID without asking anyone else. This makes them ideal for microservices, multi-region deployments, and offline-first clients. A mobile app can create records locally, assign them UUIDs, and sync later without worrying about conflicts.
Alternatives Worth Knowing
UUIDs are not the only distributed-friendly option.
Twitter Snowflake is a 64-bit ID format that packs a timestamp, a data center ID, a machine ID, and a sequence number into a single integer. The result is time-sortable, fits in a BIGINT, and avoids coordination between machines. Discord and Instagram use variations of this pattern.
MongoDB ObjectId is a 12-byte binary value that combines a 4-byte timestamp, a 5-byte machine and process identifier, and a 3-byte counter. It is smaller than a UUID, sorts roughly by time, and embeds metadata about where the document was created.
ULID (Universally Unique Lexicographically Sortable Identifier) is a 26-character string that looks like 01ARZ3NDEKTSV4RRFFQ69G5FAV. It is sortable by time, URL-safe, and case-insensitive. If you need a string format but want better index behavior than UUID v4, ULID is a strong candidate.
Each of these formats trades some randomness for structure. Snowflake IDs are predictable if you know the layout, which can be a privacy concern. UUID v4 remains the most opaque.
When to Use What
There is no universal winner. The best database ID strategy depends on your constraints.
Choose sequential IDs when:
- You run a single database instance.
- Storage and index size are critical.
- You want simple, human-readable URLs like
/users/1234. - You do not expose IDs to end users, so guessability is irrelevant.
Choose UUIDs when:
- You run multiple databases, shards, or microservices.
- You generate IDs on the client or in edge functions.
- You need opaque identifiers that cannot be guessed or enumerated.
- You anticipate merging datasets from different sources later.
Consider hybrids when:
- You want time-sortability but need distributed generation. ULID, UUID v7, or Snowflake-style IDs give you the best of both worlds.
- You need the smallest possible ID. A 64-bit Snowflake ID is half the size of a UUID.
- You want to embed metadata. MongoDB ObjectId includes creation time and origin machine by default.
Quick Decision Checklist
Use this checklist before you commit to an ID strategy:
- Is your system distributed? If yes, avoid pure sequential IDs.
- Do users see the ID in URLs or APIs? If yes, prefer opaque formats to prevent enumeration attacks.
- Is index size a hard constraint? If yes, consider BIGINT Snowflake IDs or binary UUID storage.
- Do you need time-sortable IDs? If yes, look at ULID, UUID v7, or Snowflake.
- Are you building a prototype? If yes, sequential IDs are fine. Migration is painful but not impossible if you plan early.
The debate between UUID vs sequential ID is not about which is better in absolute terms. It is about which fits your system. Pick the format that solves your real problems today, and remember that you can always migrate if your architecture changes. If you want to experiment with how UUIDs look and feel, Randify’s UUID Generator is a fast way to generate batches for testing.