UUID vs GUID: What's the Actual Difference?
Published January 15, 2026 · 12 min read · by the OnlineToolsPro team
Two years ago, I spent four hours debugging a production issue that came down to one thing: my code generated a UUID v1 instead of a v4, and the v1 was leaking the MAC address of the server it ran on. That was the day I stopped treating UUID and GUID as synonyms.
Most blog posts about this topic tell you they're the same thing. Technically, that's true — they're both 128-bit identifiers formatted as 32 hex characters in 8-4-4-4-12 grouping. Every GUID is a valid UUID, and every UUID will work wherever a GUID is expected. So why does anyone care?
Because the history matters. And because the version you pick matters more than the name. Let me walk you through what I learned the hard way, so you don't have to.
The History (Why There Are Two Names for the Same Thing)
In the early 1990s, two groups needed the same thing: a way to generate unique identifiers across distributed systems without coordinating with a central server. Microsoft was building Windows and COM (Component Object Model) and needed IDs for classes, interfaces, and type libraries. Meanwhile, the Open Software Foundation (OSF) — a consortium including Apollo, DEC, HP, IBM, and others — was working on the Distributed Computing Environment (DCE) and had the same problem.
Both groups independently landed on a similar design: a 128-bit identifier, big enough that you could generate one randomly and be essentially guaranteed never to collide with anyone else's. Microsoft called theirs GUID (Globally Unique Identifier). The OSF/IETF group called theirs UUID (Universally Unique Identifier). Same idea, two different names, two different sets of docs.
The IETF formalized UUID in RFC 4122 in 2005, and Microsoft eventually published its GUID format as a standard that conformed to RFC 4122. So today, when you generate a GUID in .NET or a UUID in Python, you're producing the same kind of value. The names are interchangeable in code. The history, though, explains why both terms persist.
You'll see GUID most often in Microsoft contexts — SQL Server's uniqueidentifier type, COM class IDs, Windows registry, .NET's Guid.NewGuid(). UUID is the term everywhere else: web standards, Linux, PostgreSQL's uuid type, JavaScript's crypto.randomUUID(), Python's uuid module.
The Format (What They Both Look Like)
Both are 128 bits, written as 32 hexadecimal digits in five groups separated by hyphens:
550e8400-e29b-41d4-a716-446655440000
The version lives in the first hex digit of the third group (the 4 in 41d4 above). The variant lives in the first hex digit of the fourth group (the a in a716, where the high two bits are 10, indicating RFC 4122). These two markers are how parsers know which algorithm generated the UUID and which version of the spec it conforms to.
You can also see UUIDs without hyphens (32 chars flat) or with curly braces (Microsoft style). They're all the same identifier, just different presentations.
The Version Matters More Than the Name
This is the part I wish someone had explained to me earlier. When you call uuid.uuid4() in Python or Guid.NewGuid() in .NET, you're getting a v4 UUID. But the UUID spec has had five versions over the years, and they behave very differently. Picking the wrong one can leak data, hurt database performance, or generate predictable identifiers.
Version 1: Time + MAC address
This is the original UUID design. The first 48 bits are a timestamp (with 100-nanosecond precision, starting from October 15, 1582 — the date of the Gregorian calendar reform, because of course it is). The next 16 bits are a "clock sequence" to handle cases where the clock is set back. The last 48 bits are the hardware MAC address of the machine generating the UUID.
The MAC address part is the privacy problem. If you generate v1 UUIDs on a server and they end up in user-facing URLs or logs, an attacker can extract the MAC address and use it to fingerprint your infrastructure. Worse, every UUID generated by the same machine shares a prefix, which means a small data leak (say, two UUIDs in different parts of your app) reveals the generating machine and lets an attacker correlate them.
Modern UUID libraries have tried to fix this by using a random MAC address instead of the real one, but the timestamp is still in there, which is its own information leak (you can tell when an ID was generated, down to 100 nanoseconds). Avoid v1 in any modern application.
Version 3: MD5 namespace hash
v3 UUIDs are deterministic — same input always produces the same UUID. You give it a "namespace" UUID and a name, and it computes MD5(namespace || name), then sets the version and variant bits. The result is that uuid.uuid3(NAMESPACE_DNS, "example.com") always returns the same UUID, no matter who runs it or when.
Deterministic UUIDs are useful when you want to merge data from different sources without coordinating. If two services both compute UUIDs from a stable identifier like an email address, they can store them in the same database without conflict. But MD5 is broken for cryptographic purposes (and deprecated in many standards), so v5 is preferred for new code.
Version 4: Random
122 bits of pure randomness. This is what most people mean when they say "UUID." It's what crypto.randomUUID() in the browser produces, what Guid.NewGuid() returns in .NET, and what most "UUID generator" tools create by default.
Collision probability is essentially zero for any realistic use case. A v4 UUID has 2^122 = 5.3 × 10^36 possible values. Even if you generated 1 billion UUIDs per second, you'd need to run for 85 years to have a 50% chance of a single collision. The birthday paradox threshold (where collisions become likely in a set) is around 2.71 quintillion UUIDs, which is not a number you will ever reach.
v4 is the right choice for most new projects. The main downside: random values don't sort well. If you use them as database primary keys, new rows get inserted into random positions in the B-tree index, which is slower than appending at the end.
Version 5: SHA-1 namespace hash
Same as v3 but uses SHA-1 instead of MD5. Still deterministic, still useful for the same "merge without coordinating" use case, but more secure. RFC 4122 actually says there's no cryptographic difference between v3 and v5 in the sense that MD5 isn't used for security — just for generating the UUID — but using SHA-1 is "more culturally acceptable" (their words). For new code, pick v5 over v3.
Version 7: Time-ordered random
This is the new kid, standardized in RFC 9562 in 2024. v7 puts 48 bits of millisecond-precision Unix timestamp at the front, followed by 74 random bits. The result: UUIDs that sort chronologically but are still effectively unique.
For database primary keys, v7 is a game-changer. The timestamp prefix means new rows append to the end of the B-tree index (fast), while the random suffix means different rows generated in the same millisecond still have different keys (correct). If you've ever dealt with the "my inserts are slow because the primary key index is fragmented" problem, v7 fixes it.
PostgreSQL, MySQL 8, and CockroachDB all have native v7 functions. Most other databases (and the standard library UUID implementations) are catching up. If your stack supports v7, use it for new tables.
The Database Performance Question
If you're using a relational database, your primary key choice has real consequences. Let me walk through the tradeoffs honestly.
Auto-increment integer: Smallest possible key (8 bytes for a bigint, 4 for int), fastest comparison, naturally ordered so B-tree inserts are sequential. Downsides: reveals business data (the size of your user base is encoded in the ID), makes distributed ID generation hard, and means you can't merge data from multiple databases without conflict resolution.
UUID v4: Biggest key (16 bytes stored as 36 chars, or 16 bytes binary), fully distributed (no coordination needed), no information leak. Downsides: random order means scattered B-tree inserts (slower on large tables), bigger indexes use more memory, and a binary UUID column is awkward in some ORMs.
UUID v7: Same size as v4, distributed like v4, but ordered like an integer. The best of both worlds for new projects. Caveat: if you need the timestamp to be exact (say, for legal reasons), don't rely on it being unmodifiable — a user could detect and change it. But for most applications, "roughly when was this created" is fine.
For an e-commerce site, I'd use auto-increment for order numbers (they're naturally sequential, customers like them, and you want to display them). For user IDs, I'd use v7. For session tokens, v4 (you don't need order, and you want maximum randomness). For event log IDs, v7. For external-facing API keys, v4 with a separate secret. The choice depends on the use case.
What I'd Actually Recommend in 2026
For a new project, here's the simple decision tree I follow:
- Primary key in a relational database? Use v7 if your database supports it. Otherwise use v4, but size your indexes for it (PostgreSQL handles this well, MySQL needs a bit more care).
- Need to merge data from multiple sources without coordination? Use v5 with a stable namespace (like a domain name) and a stable input (like an email or account ID).
- Generating session tokens, API keys, or any unguessable ID? Use v4, but pull the randomness from a cryptographic source (
crypto.randomUUID()in browsers,os.urandom()in Python,RandomNumberGenerator.GetBytes()in .NET). TheMath.random()in JavaScript is fine for v4 if you don't need security against an attacker who can observe your process. - Working with .NET or Windows APIs? Just use
Guid.NewGuid()— it's v4 and there's no reason to think harder about it unless you have a specific reason. - Storing anything created before 2024? Check what you used. If it's v1, consider rotating those IDs (yes, even the pain) to avoid leaking the timestamps of your business events.
Quick Answers to Common Questions
Are UUID and GUID the same thing? Yes. They follow the same spec, produce the same format, and are interchangeable in code.
Should I use UUID or GUID in my code? Whichever your language or framework uses by default. In JavaScript and Python, it's UUID. In C# and SQL Server, it's GUID.
Is v4 always fine? For non-database use, yes. For database primary keys, prefer v7 if available.
Can I use UUIDs in URLs? Yes, but they're long (36 characters). For public-facing IDs, consider a shorter scheme like NanoID (21 chars) or ULID (26 chars).
Should I validate UUID format? Yes — use a regex to reject invalid input before it hits your database. The standard is /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, but you can be more lenient about hyphens and case.
Try It Yourself
Our free UUID Generator supports v4 and v7, with options for uppercase, hyphens, and braces. It runs entirely in your browser — your IDs are generated locally and never sent to a server. If you're working on a new project and need to test how v4 vs v7 affects your database, generate a few thousand of each and benchmark inserts. The difference is real, and it's worth seeing for yourself.
And if you're like me and have v1 UUIDs floating around in production — maybe take a quiet afternoon and plan a rotation. Future you will thank present you.
What About NanoID, ULID, and Other Alternatives?
UUID is the default choice, but it's not the only one. Two alternatives have gained real traction: NanoID and ULID. Both address the same problem (unique identifiers) but with different tradeoffs.
NanoID is a tiny JavaScript library that generates 21-character random IDs using a URL-safe alphabet (A-Za-z0-9_-). The default 21-character ID has 126 bits of entropy, comparable to a UUIDv4. The library is 130 bytes minified, so it doesn't add meaningful weight to your bundle. The IDs are shorter than UUIDs (21 chars vs 36), which matters for URL slugs and database storage.
NanoID is popular in the JavaScript ecosystem for cases where you want a short, random ID without bringing in a UUID library. If you're working in JavaScript and want a short random ID, NanoID is a good choice.
ULID (Universally Unique Lexicographically Sortable Identifier) is 26 characters, time-ordered like UUIDv7, and uses Crockford's base32 encoding (which excludes easily-confused characters like I, L, O, U). The format is 01ARZ3NDEKTSV4RRFFQ69G5FAV — 10 characters for the timestamp, 16 for the randomness. ULIDs sort lexicographically by creation time, which means they work as natural primary keys.
ULID is more popular in polyglot environments where you need a time-ordered ID that isn't tied to the UUID spec. PostgreSQL has native ULID support, and most languages have libraries for generating them.
For most use cases, I'd still use UUIDv7 — it's standardized (RFC 9562), supported by major databases, and has the broadest tooling. But NanoID and ULID are legitimate alternatives when the tradeoffs matter.
The Short Version, If You Skimmed
UUID and GUID are the same thing with different names. Use UUIDv4 for general-purpose random IDs, UUIDv7 for database primary keys (when supported), UUIDv5 for deterministic IDs from stable inputs. Avoid UUIDv1. Use a proper library, not hand-rolled code. Validate input. Generate billions without worrying about collisions. The end.