One GUID, two byte orders
A GUID is 16 bytes. The string 12345678-9abc-def0-1234-56789abcdef0 shows them in RFC 9562 order, and that is what PostgreSQL, Java, Python, MySQL's UUID_TO_BIN and JavaScript use. .NET's Guid.ToByteArray(), new Guid(byte[]), SQL Server's uniqueidentifier and Oracle's ODP.NET write the first three groups little-endian instead: 78 56 34 12 bc 9a f0 de 12 34 56 78 9a bc de f0. Nothing is wrong with either; problems start when bytes cross from one world to the other, for example a Base64 ID made from ToByteArray() and decoded in Java, or a RAW(16) written by .NET and compared with SYS_GUID(). Since .NET 8, ToByteArray(bigEndian: true) gives the RFC order.
Version 7 GUIDs and SQL Server
Guid.CreateVersion7() (.NET 9 and later) starts with a 48-bit Unix millisecond timestamp, so its values sort by creation time as strings, in Guid.CompareTo and in PostgreSQL. SQL Server compares uniqueidentifier values starting with the last six bytes, which in a version 7 GUID are random, so a clustered index on them fragments like one on random GUIDs. The sort panel above shows it. For SQL Server, use NEWSEQUENTIALID() as the column default, or EF Core's client-side SequentialGuidValueGenerator (its default for Guid keys on SQL Server), which writes a counter into exactly the bytes SQL Server compares first.
On PostgreSQL the picture flips: the Npgsql EF Core provider (checked with 10.0.3) generates version 7 GUIDs for Guid keys, which suit PostgreSQL's byte-by-byte order.
Also: .NET keeps no counter within a millisecond, so version 7 GUIDs created in the same millisecond are in random order. We measured about half of consecutive values out of order in a tight loop.
Name-based GUIDs: UUID version 5
A version 5 GUID is computed, not random: SHA-1 over a namespace GUID and a name, cut to 16 bytes, with the version and variant bits set (RFC 9562). The same namespace and name always give the same GUID, in any language, so two systems can derive the same ID for "code-maze.com" without talking to each other. Use it for stable IDs derived from natural keys, such as a URL, an email address or an external system's ID.
.NET has no built-in for it. The helper under the generator is all you need (.NET 8+ for the big-endian Guid overloads); it gives the same results as Python's uuid.uuid5, which we checked on hundreds of names. The standard namespaces are DNS, URL, OID and X.500; for your own IDs, create one random namespace GUID and keep it fixed. Version 3 is the same scheme with MD5, and RFC 9562 prefers version 5. Anyone who knows the name can compute the GUID, so never use one as a secret or an unguessable token.
What Guid.Parse accepts
- Five formats:
N(32 digits),D(hyphens),B(braces),P(parentheses) andX({0x12345678,0x9abc,...}), in any case, with surrounding whitespace. - In
D,BandP, each group may start with+or0x:+2345678-9abc-def0-1234-56789abcdef0is a valid GUID.Nrejects both. - In
X, whitespace anywhere is ignored and the second and third fields are cut to 16 bits:0x19abcbecomes9abc. urn:uuid:prefixes, square brackets and a leading byte order mark are rejected.
If you validate user input with Guid.TryParse, these all pass. Guid.TryParseExact(s, "D", out var g) still allows the + and 0x forms, so compare g.ToString("D") with the input if you need the canonical form only.
FAQ
Why do ToByteArray() bytes not match the GUID string?
The first three fields are written little-endian. Use ToByteArray(bigEndian: true) (.NET 8+) for RFC order.
Are CreateVersion7() values sequential in SQL Server?
No: SQL Server compares the last six bytes first, and they are random. Use NEWSEQUENTIALID() or EF Core's sequential generator.
Are two CreateVersion7() values from the same millisecond in order?
Not necessarily. .NET keeps no counter within a millisecond.
Does Guid.Parse accept "+" or "0x" inside a GUID?
Yes, at the start of each group in the hyphenated formats. The 32-digit format does not.
How do I create a UUID v5 in C#?
.NET has no built-in. Hash the namespace (ToByteArray(bigEndian: true)) and the UTF-8 name with SHA-1, set the version and variant bits, and build the GUID with new Guid(bytes, bigEndian: true). The generator above shows the full helper.
Why does a GUID stored by .NET in Oracle RAW(16) look different?
ODP.NET binds Guid.ToByteArray(), while SYS_GUID() and most clients use RFC order.