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 (name-based)
  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.NewDatabaseFriendly(Database.PostgreSql);   // v7

v5 Guid (name-based)

.NET has no built-in API for name-based (v5) Guids. Use a package such as UUIDNext:

// dotnet add package UUIDNext
using UUIDNext;
Guid id = Uuid.NewNameBased(Uuid.Namespace.URL, "https://example.com");

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{0x0e6f1b8c,0x2c33,0x4f1f,{0x9c,0x0b,...}}C/C++ struct literal

Guid.ToString() returns lowercase hex on every .NET version, including .NET Framework. Call .ToUpperInvariant() if you need uppercase.

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 sequential variant that increases on one machine, but it can start again from a lower range after Windows restarts, and its values are guessable. For cross-platform v7, generate in C# with Guid.CreateVersion7() and pass the value in (see the SQL Server ordering note under “Common pitfalls”).

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 Guid ↔ uniqueidentifier 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 (needs a package)Uuid.NewNameBased(Uuid.Namespace.URL, name) (UUIDNext)
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