UUID vs GUID: What Is Actually Different

GUID is Microsoft's name for a UUID. The differences you meet in practice are text formatting, byte order when the value is stored as 16 bytes, and SQL Server's sort order.

If you only need the short answer: a GUID and a UUID are the same kind of value, a 128-bit identifier usually written as 32 hex digits in five groups. Guid.NewGuid() in .NET and crypto.randomUUID() in JavaScript both produce random version 4 UUIDs. Interoperability problems still happen, though, and they come from three places: how the value is written as text, how its 16 bytes are ordered, and how SQL Server compares it.

Two names for one standard

UUIDs come from Apollo's Network Computing System and were carried into the OSF Distributed Computing Environment. Microsoft adopted the DCE design for COM and called the values globally unique identifiers. The IETF later published the format as RFC 4122 in July 2005, which was replaced in May 2024 by RFC 9562, the version that added UUID v6, v7 and v8. Both RFCs say outright that UUIDs are also known as GUIDs.

One field records the naming history. The variant bits at the start of the fourth group distinguish RFC UUIDs, where that group starts with 8, 9, a or b, from a range reserved for Microsoft backward compatibility, starting with c or d. GUIDs created by current Windows and .NET use the RFC variant, so in practice the two are indistinguishable.

Text formats

.NET's Guid.ToString() takes a format specifier. These are the outputs for the same value in .NET 8:

SpecifierOutput
Nf47ac10b58cc4372a5670e02b2c3d479
D (default)f47ac10b-58cc-4372-a567-0e02b2c3d479
B{f47ac10b-58cc-4372-a567-0e02b2c3d479}
P(f47ac10b-58cc-4372-a567-0e02b2c3d479)
X{0xf47ac10b,0x58cc,0x4372,{0xa5,0x67,0x0e,0x02,0xb2,0xc3,0xd4,0x79}}

All of them are lowercase. The uppercase style with braces, {F47AC10B-58CC-4372-A567-0E02B2C3D479}, comes from the Windows registry, COM class IDs and Visual Studio project files, and SQL Server displays uniqueidentifier values in uppercase too. RFC 4122 asks for lowercase output and case-insensitive input, and Guid.Parse accepts every form in the table.

The practical rule: never compare GUIDs as strings. "{F47AC10B-...}" and "f47ac10b-..." are different strings and the same value. Parse both sides, or normalise to lowercase without braces before storing or comparing.

Byte order: the difference that bites

Stored as 16 bytes, an RFC UUID is big-endian: the bytes come in the same order as the hex digits. Microsoft's GUID structure is different. It is declared as a 32-bit integer, two 16-bit integers and 8 single bytes, and on little-endian machines the three integers are stored with their bytes reversed. Guid.ToByteArray() returns exactly that layout, and new Guid(byte[]) expects it:

Text:           f47ac10b-58cc-4372-a567-0e02b2c3d479
RFC bytes:      f4 7a c1 0b  58 cc  43 72  a5 67  0e 02 b2 c3 d4 79
ToByteArray():  0b c1 7a f4  cc 58  72 43  a5 67  0e 02 b2 c3 d4 79

The last 8 bytes are identical; the first three groups are reversed. SQL Server uses the same mixed-endian layout: converting a uniqueidentifier to binary(16) gives the ToByteArray() bytes.

The bug appears when one side writes bytes in one layout and the other side reads them in the other. A .NET service writes ToByteArray() into a BINARY(16) column or a binary message; a Java, Go or Python service reads the bytes as an RFC UUID and gets 0bc17af4-cc58-7243-a567-0e02b2c3d479. The value is still unique, so nothing fails, but lookups between the two systems never match. The version digit moved too: in this example the scrambled value claims to be version 7.

Pick one layout and convert explicitly at the boundary:

  • .NET 8 and later: guid.ToByteArray(bigEndian: true) and new Guid(bytes, bigEndian: true) read and write RFC order.
  • Python: uuid.UUID(bytes_le=data) reads the Microsoft layout, and u.bytes_le writes it.
  • Anywhere: if you store text or a native UUID type instead of raw bytes, the question never comes up.

How SQL Server sorts uniqueidentifier

SQL Server does not sort GUIDs the way their text reads. It compares the last group of six bytes first, then the fourth group, then the third, second and first groups, and inside those first three groups the rightmost byte counts most. This list is in ascending uniqueidentifier order, as produced by .NET's SqlGuid type, which implements the same comparison:

01000000-0000-0000-0000-000000000000
ff000000-0000-0000-0000-000000000000
00000001-0000-0000-0000-000000000000
00000000-0100-0000-0000-000000000000
00000000-0001-0000-0000-000000000000
00000000-0000-0100-0000-000000000000
00000000-0000-0001-0000-000000000000
00000000-0000-0000-0001-000000000000
00000000-0000-0000-0100-000000000000
00000000-0000-0000-0000-000000000002
00000000-0000-0000-0000-010000000000

Sorting the same values as System.Guid in .NET, or as strings in any language, gives a different order: 00000000-0000-0000-0000-000000000002 comes first and ff000000-0000-0000-0000-000000000000 last. Two consequences follow:

  • Keyset pagination can skip or repeat rows if the application sorts GUIDs itself and then asks SQL Server for rows WHERE id > @last. Let the database do both.
  • UUID v7 does not help in SQL Server. A v7 value starts with a timestamp, but SQL Server compares the random tail first, so v7 keys, including those from .NET 9's Guid.CreateVersion7(), land at random positions in a uniqueidentifier index just as v4 keys do.

NEWID vs NEWSEQUENTIALID

NEWID()NEWSEQUENTIALID()
How it is madeRandom, version 4Windows UuidCreateSequential, a time-based UUID, with its bytes rearranged
Where you can use itAnywhere in T-SQLOnly in a DEFAULT constraint on a uniqueidentifier column
OrderRandomIncreasing in SQL Server's sort order on that machine; may restart lower after Windows restarts
PredictableNoYes: the next value can be guessed
Index behaviourInserts land anywhere, causing page splitsInserts go to the end of the index

NEWSEQUENTIALID() exists because random keys fragment clustered indexes. The byte rearrangement is what makes its values increase under SQL Server's unusual comparison, which is also why sorting them as text does not reproduce the order they were created in. Because the values can be guessed, Microsoft's documentation advises against it where privacy matters; keep such IDs out of URLs. If keys are generated in the application instead, sorting as SQL Server does requires putting the time-based bytes in the last group, which is the opposite of what UUID v7 does.

Generating either one

Because the values are the same, any UUID v4 generator is a GUID generator. The GUID Generator produces random version 4 values in the registry style, uppercase with braces, and the UUID v4 Generator produces the same kind of value in lowercase RFC form. Both can switch braces, case and hyphens, which covers the N, D and B formats above.

Frequently Asked Questions

Is a GUID the same as a UUID?

Yes. GUID is the name Microsoft uses for the UUID format. Both are 128-bit values, and Guid.NewGuid() produces a standard random version 4 UUID.

Why does my GUID look different after reading it from the database?

The first three groups are byte-swapped. .NET's ToByteArray() and SQL Server store those groups in little-endian order, while most other languages read 16 bytes in RFC big-endian order. Convert explicitly, or store the value as text or a native UUID type.

Should GUIDs be uppercase or lowercase?

Either is valid. RFC 4122 recommends lowercase output and case-insensitive input; Windows tools and SQL Server display uppercase. Compare parsed values rather than strings.

Does UUID v7 keep SQL Server indexes in order?

No. SQL Server compares the last six bytes of a uniqueidentifier first, and in a v7 value those bytes are random. NEWSEQUENTIALID() is ordered for SQL Server; v7 is ordered for databases that compare bytes from left to right.