Email me

Explainer · 4 min read

Filed under App development Guides

.NET Guid byte order: why ToByteArray() and SQL Server sort your GUIDs wrong

Short answer

Guid.ToByteArray() in .NET is mixed-endian: it reverses the first three groups of the GUID (4, 2 and 2 bytes) and leaves the last 8 bytes as written. SQL Server's uniqueidentifier sorts in yet another order, with the last six bytes most significant. So a time-ordered UUIDv7 stops being time-ordered the moment you store it either way. The fix on .NET 8+: ToByteArray(bigEndian: true) into a binary(16) column.

Card: the same GUID 018f3a2b-7c4d-7e5f-8a9b-0c1d2e3f4a5b written by ToByteArray() as 2B 3A 8F 01, 4D 7C, 5F 7E, then 8A 9B 0C 1D 2E 3F 4A 5B, with the first three groups reversed; and by ToByteArray(bigEndian: true) in .NET 8+ as 01 8F 3A 2B 7C 4D 7E 5F 8A 9B 0C 1D 2E 3F 4A 5B, the same order as the string.
Same GUID, two byte orders. Only the big-endian one sorts like the string. Card by Tensorust from Microsoft's Guid.ToByteArray docs.

Part of the article Pick a UUIDv7 library that keeps order: 10 tested, .NET fails 50%. This page answers one question from it in depth.

On this page · 8 sections
  1. Key facts
  2. The three byte orders
  3. Why UUIDv7 breaks
  4. The fix
  5. Common misconceptions
  6. Related
  7. FAQ
  8. Sources

This is a 1990s Windows layout decision still taxing every .NET shop that adopts UUIDv7 in 2026. Nobody announces it; your index just fragments and your "sort by id" quietly lies. We found it while testing UUIDv7 libraries across languages, and counted the damage.

Key facts

What Fact Source (checked Oct 26 2026)
ToByteArray() layout first 4-byte and next two 2-byte groups reversed, last 8 bytes as in the string Microsoft Learn: Guid.ToByteArray
Big-endian overload ToByteArray(bool bigEndian), .NET 8 and later Microsoft Learn: Guid.ToByteArray
UUIDv7 in .NET Guid.CreateVersion7(), .NET 9 and later, RFC 9562 Microsoft Learn: Guid.CreateVersion7
SQL Server sort last six bytes most significant Microsoft Learn: Comparing GUID and uniqueidentifier values
UUIDv7 timestamp position first 48 bits (bytes 0 to 5) RFC 9562, section 5.7
Our count, ToByteArray() bytes in binary(16) 234 backward steps per minute at 1 ID per ms Our UUIDv7 library test

The three byte orders

Take one GUID, 018f3a2b-7c4d-7e5f-8a9b-0c1d2e3f4a5b:

  • String / RFC order: 01 8F 3A 2B 7C 4D 7E 5F 8A 9B 0C 1D 2E 3F 4A 5B
  • ToByteArray(): 2B 3A 8F 01 4D 7C 5F 7E 8A 9B 0C 1D 2E 3F 4A 5B
  • SQL Server compare order: starts at 0C 1D 2E 3F 4A 5B, the last six bytes, then works back through the groups.

The .NET layout mirrors the old Windows GUID struct: a 32-bit field, two 16-bit fields, then 8 raw bytes, with the integers stored little-endian on x86. Microsoft's own example shows 35918bc9-... coming out as C9 8B 91 35 ....

Card: byte groups 0-3, 4-5, 6-7, 8-9, 10-15. Guid.CompareTo and the string sort 0-3 first through 10-15; a binary(16) of ToByteArray() bytes sorts mixed-endian bytes; SQL Server uniqueidentifier sorts 10-15, then 8-9, 6-7, 4-5, 0-3. UUIDv7 puts the timestamp in bytes 0-5, so a v7 GUID in a uniqueidentifier key is not time-ordered. Where each system starts comparing. Card by Tensorust from Microsoft's docs and RFC 9562.

Why UUIDv7 breaks

UUIDv7 exists to be sortable: the millisecond timestamp sits in the first six bytes, big-endian, so newer IDs compare larger (see UUIDv7 vs UUIDv4). Two things undo that in .NET:

  1. ToByteArray() into binary(16). The flip puts the low bytes of the timestamp's first group ahead of its high bytes, so stored order jumps backward every 256 ms when the low byte rolls over. Our run, one CreateVersion7() per millisecond: 234 backward steps per minute. With ToByteArray(bigEndian: true): zero.
  2. uniqueidentifier columns. SQL Server compares the last six bytes first. In a v7 GUID those are random, so inserts land all over the index: the exact page-split problem UUIDv7 was meant to fix.

Card: our count. One Guid.CreateVersion7() per millisecond stored as ToByteArray() bytes in binary(16): 234 backward steps per 60,000 IDs; with ToByteArray(bigEndian: true): 0. From our UUIDv7 library test. One ID per millisecond for one minute.

The fix

  • Bytes: on .NET 8+, always write guid.ToByteArray(bigEndian: true) and read back with new Guid(bytes, bigEndian: true). Store in binary(16) and the sort matches time.
  • SQL Server keys: if the column must stay uniqueidentifier, do not rely on v7 for insert order. Use an ID whose last bytes increase (SQL Server's NEWSEQUENTIALID() works that way) or cluster on a datetime2 or bigint column.
  • Order inside one millisecond: CreateVersion7() fills the rest with random bits, so IDs from the same millisecond are not ordered among themselves; our library test measured that too. To pull the timestamp back out and check, see how to extract the timestamp from a UUIDv7.

Common misconceptions

Myth

"A GUID is just 16 bytes, order does not matter."

The recordIt matters the moment you sort or index the bytes. The string, .NET's array and SQL Server disagree on which byte comes first.

Myth

"CreateVersion7() makes SQL Server keys sequential."

The recordNot in a uniqueidentifier column. SQL Server reads the random tail first.

Myth

"ToByteArray() follows the CPU's endianness."

The recordThe documented layout is fixed; use the bigEndian overload when you want RFC order.

FAQ

What byte order does Guid.ToByteArray() use?

Mixed-endian. Per Microsoft's docs, the first four-byte group and the next two two-byte groups are reversed (little-endian), while the last two-byte group and the six-byte group stay in the order of the string.

How do I get a GUID's bytes in big-endian order in .NET?

On .NET 8 or later call guid.ToByteArray(bigEndian: true). It writes the 16 bytes in the same order as the string form, which is the RFC 9562 order.

How does SQL Server sort uniqueidentifier?

Not by the string. Microsoft documents that SqlGuid and SQL Server treat the last six bytes as most significant. The commonly observed full order is bytes 10 to 15, then 8 to 9, 6 to 7, 4 to 5 and 0 to 3.

Is Guid.CreateVersion7() sortable in SQL Server?

Not as a uniqueidentifier key. UUIDv7 puts the timestamp in the first six bytes, and SQL Server compares the last six bytes first, which are random. Store it as binary(16) written with ToByteArray(bigEndian: true), or keep a separate time column for ordering.

Which .NET version added CreateVersion7?

.NET 9 added Guid.CreateVersion7(), following RFC 9562.

Sources

All checked October 26, 2026.

Next question

Every number on this page links to its source and was checked on Oct 26, 2026. Spot an error or a newer figure? Email matt@tensorust.com and it gets fixed.

Read next

Back to The Manual →   All articles →

Get the next one by email.

What my AI agents tried this week, with the real numbers: what worked, what flopped, what made money. One email when there is something worth reading.

No spam, never sold. Every email has a one-click unsubscribe.

Up next

The article this answer comes fromPick a UUIDv7 library that keeps order: 10 tested, .NET fails 50%We tested 10 UUIDv7 libraries with 1M IDs each and a clock jump. .NET put 50% out of order, uuid6 ran 16.6 min ahead. The 2 that passed, plus free data.Read it next →

Art: Nicholas Roerich, Depsang Plains (1925-26). Public domain, via Wikimedia Commons.

Get the receipts by email.

What my AI agents tried this week, with the real numbers: what worked, what flopped, what made money. One email when there is something worth reading.

No spam, never sold. Every email has a one-click unsubscribe.

Did this answer your question?

Popular in the shop

All 124 tools →

Browse: Bundles and kitsHome, family and schoolMoney and businessAI toolsSports and fitnessMaking and hobbiesFood and drinkIndie dev and launchTrading and quant

Free: Landing page teardown iPhone app cost calculator LLM API cost calculator Paid online: $49 Launch Check App builds Articles FAQ

Disagree, or have a number to add? Discuss this on The Floor →

What are people saying about this? Read and post on The Floor →