Everything You Need to Know About UUIDs
What Is a UUID?
A UUID, or Universally Unique Identifier, is a 128-bit value used to label data in a way that's globally unique without needing a central authority to hand it out. In its standard form, it's displayed as 32 hexadecimal digits split into five groups by hyphens, something like this: 550e8400-e29b-41d4-a716-446655440000.
The magic here is that any machine, anywhere, with no network connection and no coordination with any other system, can generate a UUID and be confident it won't collide with one generated somewhere else. That's a huge deal once you start building distributed systems, microservices, or offline-capable apps, where you simply can't rely on one central database counting up integers for you.
GUID vs UUID: Same Idea, Different Name
If you've spent time in the .NET or Windows world, you've probably said GUID (Globally Unique Identifier) way more often than UUID. Good news: you don't need two mental models, because they're the same thing.
The naming split is purely historical. Microsoft's GUID predates RFC 4122, the document that officially standardized UUIDs back in 2005. Microsoft had already built GUIDs into COM, the Windows registry, and ActiveX years before that RFC existed, so "GUID" was already deeply embedded in developer vocabulary and tooling before "UUID" became the formal, cross-platform term. RFC 4122 essentially took the ideas that vendors like Microsoft and the Open Software Foundation had already been using and turned them into an open, universal spec.
Practically speaking, treat GUID and UUID as interchangeable. The one caveat worth knowing: Microsoft's internal binary representation of a GUID historically uses a different byte ordering (endianness) in some fields compared to the standard UUID byte layout. This almost never matters unless you're doing low-level binary interop between a .NET system and a non-Windows system, but it's good trivia to have in your back pocket.
How Are UUIDs Actually Used?
Two use cases come up constantly for any working developer: primary keys and slugs.
As a primary key, a UUID can be generated the moment a record is created, in application code, before it ever touches a database. That means you're not waiting on the database to hand you an auto-incremented ID before you can reference that record somewhere else in your system, log it, or queue it for async processing. This is especially valuable in event-driven architectures, message queues, and offline-first mobile apps where records might be created before there's even a network connection available.
As a slug or public identifier, UUIDs shine because they don't leak information. If your app exposes URLs like /invoices/1024, it's trivial for anyone to guess /invoices/1025 and start poking around your system, which is a real enumeration and privacy risk. Swap that for /invoices/9c858901-8a57-4791-81fe-4c455b099bc9, and there's nothing to guess. This is why UUIDs are everywhere in API tokens, session IDs, file keys in cloud storage buckets, and any resource identifier you don't want to be predictable.
You'll also run into UUIDs as correlation IDs in distributed tracing, letting you follow one request across a chain of microservices in your logging and observability stack, as idempotency keys for safely retrying API calls and payment operations, and as identifiers for background jobs, feature flags, and database migrations.
How Unique Are UUIDs in the Real World?
Short answer: unique enough that you genuinely don't need to worry about it, assuming you're using a proper implementation.
Take the most common type, version 4, which is generated using random or pseudo-random numbers. Of the 128 total bits, 122 are available for randomness (the rest are reserved to mark the version and variant). That works out to 2^122 possible values, roughly 5.3 undecillion combinations. The commonly cited stat is that you'd need to generate around a billion UUIDs every second for about 85 years before you'd hit even a 50% chance of a single collision. Realistically, you're far more likely to run into a hardware failure or a bug in your own code than an actual UUID collision.
The catch is that this uniqueness guarantee depends entirely on solid random number generation. Any mainstream language's standard UUID library handles this correctly using a cryptographically secure random number generator, so you're fine in the vast majority of cases. Where things break down is in poorly seeded or custom implementations, certain low-entropy embedded environments, or version 1 UUIDs, which embed a timestamp and the generating machine's MAC address. Version 1 has strong uniqueness properties too, but it comes with a privacy tradeoff worth knowing about, since it can leak hardware and timing details.
UUID Versions at a Glance
The UUID spec isn't one algorithm, it's a family of them, each suited to different needs. Here's the quick rundown:
| Version | Generation Method |
|---|---|
| 1 | Timestamp + MAC address |
| 2 | DCE Security, rarely used |
| 3 | Name-based, MD5 hash |
| 4 | Random or pseudo-random |
| 5 | Name-based, SHA-1 hash |
| 6 | Reordered timestamp for sortability |
| 7 | Unix timestamp, sortable, database-friendly |
| 8 | Custom, vendor or application-defined layout |
Version 4 is what most developers reach for by default, pure randomness, no metadata leakage, dead simple to generate. Versions 3 and 5 are name-based and deterministic, meaning the same namespace plus name always produces the same UUID, which is handy when you need repeatable IDs rather than random ones. Version 1 works fine but leaks timing and hardware info. Version 2 exists on paper but you'll almost never see it used. Versions 6, 7, and 8 are the newer additions from RFC 9562, built specifically to solve sortability and database performance problems that the original spec never addressed.
Why UUID Version 7 Is Becoming the New Standard
If you're starting a new project today, version 7 deserves your attention, and it's quickly becoming the default recommendation for anyone generating UUIDs for database use.
The problem with version 4 is that it's completely random, which means every new UUID lands in a random spot in your index rather than at the end. Version 7 fixes this by embedding a Unix timestamp, down to millisecond precision, in the leading bits of the value, with the remaining bits filled with randomness for uniqueness within that same millisecond. The result is a UUID that's still effectively collision-resistant, but that also sorts chronologically, the same way an auto-incrementing integer or a timestamp column would.
That sortability is a big deal in practice. It means better B-tree index locality on insert, fewer page splits, better cache behavior, and IDs that naturally sort by creation time without needing a separate created_at column just to order things. You get the distributed, coordination-free generation that made UUIDs useful in the first place, plus the performance characteristics that made sequential integers attractive. It's genuinely the best of both worlds, which is why you'll see version 7 showing up as the recommended default in newer ORMs, frameworks, and database drivers.
Are UUIDs Suitable for Database Primary Keys?
This is genuinely debated among backend developers and DBAs, and the honest answer is: it depends on your database engine, your scale, and which UUID version you pick.
The case for UUIDs as primary keys is solid. You can generate them client-side or application-side before an insert, which makes distributed inserts, data merges, and replication across multiple sources far simpler, since you never have to worry about ID collisions between systems. They also don't expose row counts or creation order the way sequential integers do, which is a nice security property for anything customer-facing.
The traditional case against them comes down to indexing performance with version 4. Since it's fully random, new rows land at random points throughout a B-tree index instead of being appended at the end, causing fragmentation, extra page splits, and worse cache locality, especially in engines like MySQL's InnoDB where the primary key doubles as the clustered index. This is precisely the gap version 7 closes, giving you sequential, insert-friendly behavior without giving up the benefits of decentralized generation. If you're designing a new schema today, version 7 is generally the smarter default over version 4 for primary keys.
A popular compromise some teams still use: a sequential integer internally for fast joins and compact indexes, with a separate UUID column exposed publicly for your API and URLs. With version 7 in the mix, though, plenty of teams are comfortable using UUIDs as the primary key directly and skipping that extra column entirely.
A Quick Note on Testing and Tooling
If you're a QA engineer or tester, UUIDs come up constantly in test data generation, mocking API responses, and seeding databases for integration tests. Because UUIDs are collision-resistant by design, they're a reliable way to generate unique test fixtures without worrying about clashing with existing data, which is exactly why tools like this one exist, so you can grab a batch of valid UUIDs on demand without writing a script for it.
A Note on Formatting and Storage
Worth knowing before you wire UUIDs into a schema: the canonical text representation is 36 characters including hyphens, but under the hood it's just 16 raw bytes. Most modern databases give you a native UUID type (Postgres has one built in), and you should use it instead of storing UUIDs as plain text or VARCHAR. A native UUID column takes up half the storage of the hyphenated string form and indexes more efficiently, since the database can compare raw bytes instead of parsing and comparing characters. If your database or ORM doesn't have a native type, storing the value as a binary(16) column is the next best thing, with plain text as a last resort.
Also worth flagging for security-conscious teams: UUIDs are unique, but they are not automatically unpredictable in a cryptographic sense unless you're using a version and implementation designed for that. Version 4 UUIDs generated with a proper CSPRNG are safe to use in security-sensitive contexts like password reset tokens, but don't assume every UUID generator out there meets that bar. Check your library's documentation before relying on a UUID as a secret.
Bottom Line
UUIDs solve a real, hard problem: generating unique identifiers across distributed systems without central coordination. Whether your team calls them UUIDs or GUIDs, the concept is the same, and knowing where they fit best, as primary keys, slugs, correlation IDs, or test data, along with picking the right version and storage type for the job, will save you headaches down the line. Default to random (version 4) when you just need a unique value with no ordering requirement, and reach for time-ordered (version 7) when insert performance and natural sort order actually matter, which for most new database designs, they do.
More Information About GUID Versions
For a more detailed comparison of UUID versions, visit our Complete Guide to UUID Versions.
More Information About Standards
Globally Unique Identifier - Wikipedia, the free encyclopedia
GUID Structure - Microsoft.com
RFC 9562 (2024)
RFC 4122 (2005)