UUID vs GUID: The Real Difference, UUID v4 vs v7, and the Byte Order That Breaks Migrations

UUIDs and GUIDs are, for practical purposes, the same thing: a 128-bit identifier written as 32 hex digits in groups of 8-4-4-4-12. UUID (Universally Unique Identifier) is the standard's name; GUID (Globally Unique Identifier) is Microsoft's. The one difference that matters appears in binary form, where Windows and .NET store some bytes in reverse order. That difference causes many "corrupted" IDs when data moves between SQL Server and other databases.

Same format, different name

550e8400-e29b-41d4-a716-446655440000        UUID (lower case, the usual form)
{550E8400-E29B-41D4-A716-446655440000}      GUID as Windows often displays it
└──┬───┘ └┬─┘ └┬─┘ └┬─┘ └────┬─────┘
   8      4    4    4       12  hex digits = 128 bits

The current standard is RFC 9562 (2024), which replaces RFC 4122. Microsoft implemented the same format as GUID in COM and Windows, and .NET exposes it as System.Guid. Upper case and braces are presentation only: {550E8400-…} and 550e8400-… are the same value, and comparisons should be case-insensitive.

Two fields inside every UUID are fixed. The first digit of the third group is the version (the 4 in 41d4), and the leading bits of the fourth group are the variant (the a in a716, meaning RFC 4122/9562). That is why a UUID v4 always has a 4 in that position and an 8, 9, a or b at the start of the fourth group. A quick glance tells you which version generated an ID.

The real difference: byte order

As text, UUIDs and GUIDs are identical. As bytes, they are not always. Microsoft's GUID structure stores its first three fields little-endian, and .NET's Guid.ToByteArray() returns them that way. The UUID standard is big-endian throughout.

text:         00112233-4455-6677-8899-aabbccddeeff
UUID bytes:   00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff   (RFC 9562, big-endian)
GUID bytes:   33 22 11 00 55 44 77 66 88 99 aa bb cc dd ee ff   (Guid.ToByteArray)

Copy a SQL Server uniqueidentifier as 16 raw bytes into a MySQL BINARY(16) column or another system, convert it back to text with standard rules, and you get a different UUID: the first eight bytes come out shuffled. The data is not corrupted; it was read with the other byte order. Migrate through the text representation, or convert explicitly. In Python, uuid.UUID(bytes_le=…) reads Microsoft's layout.

import uuid
u = uuid.UUID('00112233-4455-6677-8899-aabbccddeeff')
u.bytes.hex()      # '00112233445566778899aabbccddeeff'
u.bytes_le.hex()   # '33221100554477668899aabbccddeeff'  (Microsoft order)

SQL Server also sorts uniqueidentifier values unusually: it compares the last six bytes first. NEWSEQUENTIALID() values are therefore sequential only to SQL Server, not when sorted as text anywhere else.

UUID versions: v1, v4, v7 and the rest

v1   timestamp + MAC address     reveals when and on which machine it was made
v3   MD5 hash of a name          deterministic: same name -> same UUID
v4   random (122 bits)           the most widely used today
v5   SHA-1 hash of a name        like v3, with SHA-1
v6   reordered v1                time-sortable; for systems already using v1
v7   Unix milliseconds + random  time-sortable; recommended for new keys
v8   custom layout               for vendor-specific schemes

UUID v4 is what crypto.randomUUID(), uuid.uuid4() and Guid.NewGuid() return. With 122 random bits, collisions are negligible: you would need around 2.7 × 10¹⁸ random UUIDs for a 50% chance of a single duplicate. The randomness must come from a cryptographically secure source, which all standard library generators use.

UUID v7, defined in RFC 9562, starts with a 48-bit Unix timestamp in milliseconds followed by random bits. IDs generated later sort after earlier ones, which fixes v4's main weakness as a database key while keeping the other advantages of UUIDs.

UUIDs as primary keys: v4 vs v7

UUIDs let clients and multiple servers create IDs without coordination, and unlike an auto-increment 1, 2, 3, they do not reveal how many records exist or allow easy enumeration. The cost is in indexes. Random v4 values insert each row at a random point in a B-tree index, causing page splits, more write amplification and poorer cache use as the table grows.

UUID v7 inserts almost always at the end of the index, like an auto-increment key, while keeping the other benefits. For new tables it is the better default. Be aware that its prefix reveals when the record was created, which can occasionally be sensitive, for example in user or order IDs shown publicly.

Store UUIDs in native types where they exist: uuid in PostgreSQL (16 bytes), uniqueidentifier in SQL Server, or BINARY(16) in MySQL with UUID_TO_BIN() and BIN_TO_UUID(). A CHAR(36) column uses more than twice the space and makes indexes slower.

Generating UUIDs

// JavaScript (browsers in a secure context, and Node.js)
crypto.randomUUID();                       // v4

# Python
import uuid
uuid.uuid4()
uuid.uuid7()                               # Python 3.14+

// C# / .NET
Guid.NewGuid();                            // v4
Guid.CreateVersion7();                     // .NET 9+

-- PostgreSQL
SELECT gen_random_uuid();                  -- v4 (PostgreSQL 13+)
SELECT uuidv7();                           -- PostgreSQL 18+

-- SQL Server
SELECT NEWID();                            -- v4

Do not build UUIDs from Math.random() or concatenated timestamps. Library generators use a cryptographically secure random source, and that is what makes collisions improbable in practice.

Sources and further reading

RFC 9562 (Universally Unique IDentifiers) defines the format, versions 1 to 8 and the variant field, and obsoletes RFC 4122. Microsoft's documentation for System.Guid covers ToByteArray() and CreateVersion7(), and the SQL Server documentation covers uniqueidentifier and NEWSEQUENTIALID(). The Python uuid and PostgreSQL UUID function documentation cover bytes_le, uuid7(), gen_random_uuid() and uuidv7().

Frequently asked questions

What is the difference between a UUID and a GUID?

None in format or text: both are 128-bit identifiers shaped 8-4-4-4-12, and GUID is Microsoft's name for a UUID. The only practical difference is that Microsoft's GUID stores its first three fields little-endian when represented as bytes.

Is a .NET Guid a valid UUID?

Yes. `Guid.NewGuid()` produces a standard version 4 UUID. Only take care when converting it to bytes with `ToByteArray()`, which uses Microsoft's byte order.

Which UUID version should I use?

UUID v4 for general random identifiers, and UUID v7 for database primary keys, because it sorts by creation time and keeps indexes compact. Use v5 when the same name must always map to the same UUID.

Can two UUIDs be the same?

In theory yes, in practice not with a correct generator. With v4's 122 random bits you would need about 2.7 × 10¹⁸ UUIDs for a 50% chance of one collision.

Why do my GUIDs change when migrating from SQL Server?

They were copied as raw bytes, and SQL Server uses Microsoft's byte order for the first three fields. Migrate using the text form, or convert the byte order explicitly.

Are UUIDs case-sensitive?

No. `550E8400-…` and `550e8400-…` are the same UUID. RFC 9562 recommends generating lower case and comparing case-insensitively.