Skip to content
100% in your browser. Nothing you paste is uploaded — all processing runs locally. Read more →

C# / .NET Guid

On this page
  1. Generate a v4 Guid
  2. Generate a v7 Guid (.NET 9+)
  3. v5 Guid (.NET 9+)
  4. Parse from string
  5. Format specifiers
  6. Bytes — the byte-order gotcha
  7. SQL Server
  8. Entity Framework Core
  9. ASP.NET Core minimal APIs
  10. Empty Guid (nil)
  11. Common pitfalls
  12. Cheat sheet
  13. Try the tools

In .NET, UUIDs are called Guids and are represented by System.Guid — a 128-bit value type. The string form is identical to UUIDs from any other platform; the binary serialization order is the one place they differ. See UUID vs GUID.

Generate a v4 Guid

Guid id = Guid.NewGuid();
// 0e6f1b8c-2c33-4f1f-9c0b-2a3d4e5f6a7b

Guid.NewGuid() produces a v4 (random) Guid using the platform’s CSPRNG. Available since .NET Framework 1.0; works identically on .NET Core, .NET 5/6/7/8/9, and Mono.

Generate a v7 Guid (.NET 9+)

// .NET 9.0 (November 2024) and later
Guid id = Guid.CreateVersion7();
// 01928a47-3b30-7c5e-9d1a-f0b8c4a7e923

Guid id2 = Guid.CreateVersion7(timestamp: DateTimeOffset.UtcNow);

CreateVersion7 is the right default for new database primary keys — see UUID as primary key for why. For .NET 8 and earlier, install UUIDNext:

// dotnet add package UUIDNext
using UUIDNext;
Guid id = Uuid.NewSequential();   // v7

v5 Guid (.NET 9+)

Guid ns = Guid.Parse("6ba7b811-9d1d-11d1-80b4-00c04fd430c8"); // URL ns
Guid id = Guid.CreateVersion5(ns, Encoding.UTF8.GetBytes("https://example.com"));

For older .NET versions, use the UUIDNext or Faithlife.Utility.UuidUtility packages.

Parse from string

Guid id = Guid.Parse("0e6f1b8c-2c33-4f1f-9c0b-2a3d4e5f6a7b");

// Specific format (faster for hot paths)
Guid id2 = Guid.ParseExact("0e6f1b8c2c334f1f9c0b2a3d4e5f6a7b", "N");

// Try-parse for user input
if (Guid.TryParse(input, out Guid parsed)) { /* use parsed */ }

Guid.Parse accepts all five formats (N, D, B, P, X). Use ParseExact if you know the input is one specific shape — it’s faster and rejects the others.

Format specifiers

Guid.ToString() accepts a format character:

FormatExampleWhen to use
D (default)0e6f1b8c-2c33-4f1f-9c0b-2a3d4e5f6a7bLogs, JSON, URLs
N0e6f1b8c2c334f1f9c0b2a3d4e5f6a7bCompact URLs, no hyphens
B{0e6f1b8c-2c33-4f1f-9c0b-2a3d4e5f6a7b}Windows registry, COM
P(0e6f1b8c-2c33-4f1f-9c0b-2a3d4e5f6a7b)Rarely used
X{0xe6f1b8c,0x2c33,0x4f1f,{0x9c,0x0b,...}}C/C++ struct literal

Default since .NET 5 is lowercase. .NET Framework historically produced uppercase. Use g.ToString().ToLowerInvariant() if you need stable lowercase output across older runtimes.

Bytes — the byte-order gotcha

Guid g = Guid.Parse("00112233-4455-6677-8899-aabbccddeeff");
byte[] bytes = g.ToByteArray();
// 33 22 11 00  55 44  77 66  88 99  aa bb cc dd ee ff

The first three groups are stored little-endian in the byte array. This is “Microsoft order” — it’s the historical .NET / COM convention.

If you’re sending Guids over the wire to a system that expects RFC 4122 byte order (almost everything else), use ToByteArray(bigEndian: true) (.NET 8+) or do the byte-swap yourself:

// .NET 8+
byte[] rfcBytes = g.ToByteArray(bigEndian: true);

// Older
byte[] b = g.ToByteArray();
Array.Reverse(b, 0, 4);  // time_low
Array.Reverse(b, 4, 2);  // time_mid
Array.Reverse(b, 6, 2);  // time_hi_and_version
// b is now RFC byte order

For string round-trips (the canonical form) you don’t need to think about this — it’s purely a binary-serialization concern.

SQL Server

-- table
CREATE TABLE [User] (
    Id uniqueidentifier PRIMARY KEY DEFAULT NEWID(),
    Email nvarchar(256)
);

-- v4 (random) — bad for clustered index, fine for non-clustered
SELECT NEWID();

-- "sequential" — better for clustered index, but reveals partial timestamp
SELECT NEWSEQUENTIALID();

NEWSEQUENTIALID is not a UUID v7 — it’s a Microsoft-specific monotonic-within-a-machine variant. For cross-platform v7, generate in C# with Guid.CreateVersion7() and pass the value in.

Entity Framework Core

public class User
{
    public Guid Id { get; set; } = Guid.CreateVersion7(); // .NET 9+
    public string Email { get; set; }
}

// Or in OnModelCreating:
modelBuilder.Entity<User>().Property(u => u.Id)
    .HasDefaultValueSql("NEWSEQUENTIALID()"); // SQL Server-side

EF Core maps Guiduniqueidentifier automatically.

ASP.NET Core minimal APIs

app.MapGet("/users/{id:guid}", (Guid id) => GetUser(id));

The :guid route constraint validates the parameter is a parseable Guid before your handler runs. 404 on invalid input — no manual validation needed.

Empty Guid (nil)

Guid.Empty                                              // 00000000-0000-0000-0000-000000000000
Guid.Empty == Guid.Parse("00000000-0000-0000-0000-000000000000") // true

Useful as a sentinel. Don’t store it as a real entity ID; it tends to confuse libraries that treat it specially.

Common pitfalls

Cheat sheet

GoalCode
Random GuidGuid.NewGuid()
Time-ordered (DB key, .NET 9+)Guid.CreateVersion7()
Deterministic from name (.NET 9+)Guid.CreateVersion5(ns, bytes)
ParseGuid.Parse(s) or Guid.TryParse(s, out g)
Compact (no hyphens)g.ToString("N")
RFC byte orderg.ToByteArray(bigEndian: true)
EmptyGuid.Empty

Try the tools