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:

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

ApproachTypeSorts chronologically?Notes
NEWID()uniqueidentifierNoRandom — same fragmentation problem as UUID v4
NEWSEQUENTIALID()uniqueidentifierYes (single server)Cannot be used in expressions
UUID v7 + byte-swapuniqueidentifierYesApplication generates, swap applied
UUID v7 rawBINARY(16)YesLoses native GUID tooling

External references

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.