SQL Server and Azure SQL use the uniqueidentifier column type for UUIDs. It stores 16 bytes — same as PostgreSQL’s uuid — but with a byte order that diverges from the RFC 9562 standard. Understanding this difference is essential before choosing a UUID generation strategy. The Wikipedia GUID article covers the historical origins of Microsoft’s byte ordering, which predates the IETF UUID RFC. GeeksforGeeks — GUID vs UUID explains the practical implications for .NET and SQL Server developers.
The uniqueidentifier byte order problem
SQL Server stores uniqueidentifier values with the first three groups in little-endian byte order:
Standard UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Bytes (RFC): [0][1][2][3]-[4][5]-[6][7]-[8][9]-[10][11][12][13][14][15]
SQL Server: [3][2][1][0]-[5][4]-[7][6]-[8][9]-[10][11][12][13][14][15]
The last 8 bytes (the node and clock-seq groups) are big-endian — consistent with RFC. The first 8 bytes are reversed in chunks of 4, 2, and 2. This means a UUID v7 value like 018fbe3a-4c5d-7b12-8abc-0123456789ab will sort differently as uniqueidentifier than it would in PostgreSQL’s uuid type.
In practice: UUID v7 values do not sort chronologically in a SQL Server uniqueidentifier column without a byte-swap transformation.
NEWID() — random GUIDs
NEWID() is SQL Server’s built-in random GUID generator, equivalent to UUID v4:
-- Generate a random GUID
SELECT NEWID();
-- 6F9619FF-8B86-D011-B42D-00C04FC964FF
-- Column default
CREATE TABLE Orders (
Id uniqueidentifier NOT NULL DEFAULT NEWID() PRIMARY KEY,
Total int NOT NULL
);
Like UUID v4, NEWID() produces random values that fragment the clustered index as the table grows. This is the primary motivation for NEWSEQUENTIALID().
NEWSEQUENTIALID() — sequential GUIDs
NEWSEQUENTIALID() generates monotonically increasing GUIDs within a single SQL Server instance:
CREATE TABLE Orders (
Id uniqueidentifier NOT NULL DEFAULT NEWSEQUENTIALID() PRIMARY KEY,
Total int NOT NULL
);
Limitations:
- Only valid as a column
DEFAULT— you cannot call it in aSELECTorSET - Resets to a new random starting value after SQL Server service restart
- Values are sequential only within one server — not across replicas or application nodes
- The sequential property uses SQL Server’s internal byte order, not RFC byte order
For single-server applications where the database generates all IDs, NEWSEQUENTIALID() is the pragmatic choice. For distributed systems generating IDs at the application layer, use UUID v7 with a byte-swap.
UUID v7 with byte-swap for correct sorting
To use application-generated UUID v7 values that sort chronologically in SQL Server, swap the byte order when inserting and reverse it when reading. The .NET System.Guid struct has a ToByteArray() method that returns bytes in SQL Server order — use it to build the swap:
using System;
public static class UuidV7SqlServer
{
// Convert a UUID v7 string to a Guid that sorts correctly in uniqueidentifier
public static Guid ToSqlServerGuid(string uuidV7)
{
var b = new Guid(uuidV7).ToByteArray();
// Reverse the first three groups to restore big-endian order
Array.Reverse(b, 0, 4); // Data1
Array.Reverse(b, 4, 2); // Data2
Array.Reverse(b, 6, 2); // Data3
return new Guid(b);
}
}
Alternatively, use BINARY(16) to store UUID bytes in standard RFC byte order, which makes UUID v7 sort correctly without any transformation — at the cost of losing native uniqueidentifier tooling.
Entity Framework Core
Entity Framework Core supports Guid primary keys directly. To use UUID v7 with EF Core, override the value generator:
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ValueGeneration;
using Uuid = System.Guid;
public class UuidV7Generator : ValueGenerator<Guid>
{
public override Guid Next(EntityEntry entry)
=> Guid.Parse(UuidV7.Generate()); // your UUID v7 generation method
public override bool GeneratesTemporaryValues => false;
}
// In DbContext.OnModelCreating:
modelBuilder.Entity<Order>()
.Property(o => o.Id)
.HasValueGenerator<UuidV7Generator>();
Dapper and raw ADO.NET
using Dapper;
using System.Data.SqlClient;
var id = Guid.Parse(UuidV7.Generate());
await connection.ExecuteAsync(
"INSERT INTO Orders (Id, Total) VALUES (@Id, @Total)",
new { Id = id, Total = totalCents }
);
Dapper maps Guid to uniqueidentifier automatically. UUID v7 values pass through as standard Guid bytes.
Storage comparison
| Approach | Type | Sorts chronologically? | Notes |
|---|---|---|---|
NEWID() | uniqueidentifier | No | Random — same fragmentation problem as UUID v4 |
NEWSEQUENTIALID() | uniqueidentifier | Yes (single server) | Cannot be used in expressions |
| UUID v7 + byte-swap | uniqueidentifier | Yes | Application generates, swap applied |
| UUID v7 raw | BINARY(16) | Yes | Loses native GUID tooling |
Related reading
- UUID in Databases — PostgreSQL, MySQL, SQLite storage patterns
- GUID — definition and relationship to UUID
- UUID v4 vs v7 — full comparison including security and performance
- UUID v7 Generator — generate RFC 9562 v7 values in your browser
External references
- Microsoft — uniqueidentifier (T-SQL) — official reference for SQL Server’s GUID column type
- Microsoft — NEWSEQUENTIALID() — official reference for sequential GUID generation
- Entity Framework Core documentation — ORM for .NET with Guid primary key support
- RFC 9562 — UUID specification — the IETF standard defining UUID byte layout
Frequently asked questions
What is the uniqueidentifier type in SQL Server?
uniqueidentifier is SQL Server's 16-byte GUID column type. It maps to the .NET System.Guid struct and is equivalent to a UUID column in PostgreSQL. However, SQL Server stores the bytes in a non-standard order — the first three components are stored little-endian, which means UUID v7 values do not sort chronologically as uniqueidentifier without a byte-swap transformation. See Microsoft's uniqueidentifier documentation for the byte layout.
What is the difference between NEWID() and NEWSEQUENTIALID() in SQL Server?
NEWID() generates a random GUID (equivalent to UUID v4). NEWSEQUENTIALID() generates a sequential GUID that increases monotonically across calls — but only on a single server, and it resets on service restart. NEWSEQUENTIALID() only works as a column default, not as an expression in queries. For cross-server sequential IDs, use application-level UUID v7 generation with a byte-swap to respect SQL Server's byte order.
Should I use UNIQUEIDENTIFIER or BINARY(16) for UUIDs in SQL Server?
Use uniqueidentifier for full SQL Server compatibility — it has native GUI tooling support, works with Entity Framework and Dapper, and integrates with SQL Server replication. BINARY(16) lets you store UUID v7 bytes in standard byte order and sort them correctly, but you lose SQL Server's native GUID handling. Most teams use uniqueidentifier with NEWSEQUENTIALID() or application-level sequential GUID generation.