Generate database-friendly, time-ordered UUIDs anywhere in your stack — no database round-trip required.
SequentialGuid is a zero-dependency .NET library that produces RFC 9562 compliant UUIDs. Generate IDs in Blazor WebAssembly, MAUI, a background worker, or a REST controller — then pass them through your API and into the database. Because the timestamp is embedded in the value itself, you get natural sort order (dramatically reducing clustered index fragmentation), built-in timestamp extraction (no extra CreatedAt column needed), and client-side idempotency (retry-safe inserts without a server round-trip to generate a key).
Guid.NewGuid() produces random version 4 UUIDs. They work, but they fragment clustered indexes in SQL Server, PostgreSQL, and other B-tree based stores because every insert lands at a random page. SequentialGuid solves this by putting the timestamp first — new rows always append near the end of the index, just like an auto-increment integer, while still giving you the global uniqueness and merge-safety of a UUID.
| Class | RFC 9562 Section | Purpose |
|---|---|---|
GuidV4 |
§5.4 | Cryptographically random UUID — drop-in replacement for Guid.NewGuid() with guaranteed RFC 9562 version & variant bits |
GuidV5 |
§5.5 | Deterministic, namespace + name UUID using SHA-1 hashing |
GuidV7 |
§5.7 | Time-ordered UUID — 48-bit Unix millisecond timestamp + 26-bit monotonic counter (§6.2 Method 1) + 36 bits of cryptographic randomness |
GuidV8Time |
Appendix B.1 | Time-ordered UUID — 60-bit .NET Ticks (100 ns precision) + machine/process fingerprint + 22-bit monotonic counter |
GuidV8Name |
Appendix B.2 | Deterministic, namespace + name UUID using SHA-256 hashing |
- RFC 9562 compliant — correct version nibble and variant bits on every UUID, every time
- Monotonically increasing —
GuidV7andGuidV8Timeboth use a process-globalInterlocked.Incrementcounter so IDs generated on the same timestamp are still strictly ordered, even under heavy concurrency - Zero dependencies — the core package references nothing outside the BCL
- Zero allocations on modern .NET —
stackalloc,Span<T>, and[SkipLocalsInit]eliminate heap allocations on the hot path (.NET 8+) - Broad platform support — targets .NET 10 / 9 / 8, .NET Framework 4.6.2, and .NET Standard 2.0, with explicit
browserplatform support for Blazor WebAssembly - Round-trip timestamp extraction — call
.ToDateTime()on anyGuid(V7, V8, or legacy) to recover the embedded UTC timestamp — works onSqlGuidtoo - SQL Server sort-order aware —
NewSqlGuid()and.ToSqlGuid()/.FromSqlGuid()handle the byte-order shuffle so your UUIDs sort chronologically inuniqueidentifiercolumns — the only uses ofSystem.Data.SqlTypes.SqlGuidare in the obsolete legacy classes and test suite - Built-in benchmarks — a BenchmarkDotNet project is included so you can measure generation and conversion performance on your own hardware
Both generate time-ordered, sortable UUIDs. The difference is timestamp resolution and payload:
GuidV7 |
GuidV8Time |
|
|---|---|---|
| Timestamp precision | 1 ms (Unix Epoch millis) | 100 ns (.NET Ticks) |
| Counter bits | 26-bit monotonic | 22-bit monotonic |
| Random / identity bits | 36 bits of crypto-random data | 40-bit machine + process fingerprint |
| Interoperability | ✅ Standard UUIDv7 — understood by any RFC 9562 implementation | .NET-specific custom layout |
| Best for | Cross-platform / polyglot systems, general-purpose use | .NET-only systems that need sub-millisecond ordering or machine traceability |
Rule of thumb: Start with GuidV7. Reach for GuidV8Time only when you need tick-level precision or the machine/process fingerprint.
Both produce deterministic UUIDs from a namespace + name pair. The only difference is the hash algorithm:
GuidV5— Uses SHA-1 as required by RFC 9562 §5.5. Choose this when you need interoperability with UUIDv5 implementations in other languages.GuidV8Name— Uses SHA-256 as described in RFC 9562 Appendix B.2, providing a stronger hash for .NET-only scenarios.
dotnet add package SequentialGuidusing SequentialGuid;
// Millisecond precision (RFC 9562 UUIDv7) — recommended for most applications
var id = GuidV7.NewGuid();
// Sub-millisecond / tick precision (RFC 9562 UUIDv8)
var id = GuidV8Time.NewGuid();Both time-based generators provide a NewSqlGuid() method that rearranges the byte order to match SQL Server's uniqueidentifier sorting rules:
var sqlId = GuidV7.NewSqlGuid();
// or
var sqlId = GuidV8Time.NewSqlGuid();// Guaranteed RFC 9562 version & variant bits (unlike Guid.NewGuid() on some runtimes)
var id = GuidV4.NewGuid();// SHA-1 (UUIDv5) — interoperable with other languages
var id = GuidV5.Create(GuidV5.Namespaces.Url, "https://example.com");
// SHA-256 (UUIDv8 name-based) — stronger hash, .NET only
var id = GuidV8Name.Create(GuidV8Name.Namespaces.Url, "https://example.com");DateTime? created = id.ToDateTime();
// Works on GuidV7, GuidV8Time, legacy SequentialGuid, and even SqlGuid valuesvar guid = GuidV7.NewGuid();
var sqlGuid = guid.ToSqlGuid(); // reorder bytes for SQL Server
var back = sqlGuid.FromSqlGuid(); // restore standard byte ordervar id = GuidV7.NewGuid(DateTimeOffset.UtcNow);
var id = GuidV8Time.NewGuid(DateTime.UtcNow);public interface IIdGenerator
{
Guid NewId();
}
public class SequentialIdGenerator : IIdGenerator
{
public Guid NewId() => GuidV7.NewGuid();
}
// In your startup / Program.cs
services.AddTransient<IIdGenerator, SequentialIdGenerator>();public abstract class BaseEntity
{
// ID is assigned at construction — no database round-trip needed
public Guid Id { get; set; } = GuidV7.NewGuid();
// Timestamp is always available — no extra column required
public DateTime? CreatedAt => Id.ToDateTime();
}SQL Server sorts uniqueidentifier values in a non-obvious byte order. If you use SQL Server, read these two articles to understand the implications:
Use the NewSqlGuid() methods (or the .ToSqlGuid() extension) to produce UUIDs whose byte order aligns with SQL Server's comparison logic. The .FromSqlGuid() extension on Guid reverses the transformation — the name clearly conveys the intent of converting from SQL Server byte order back to the standard layout.
| Package | Purpose |
|---|---|
| SequentialGuid.NodaTime | Extension methods for Instant, OffsetDateTime, and ZonedDateTime — generate and extract timestamps using NodaTime types |
| SequentialGuid.MongoDB | Drop-in IIdGenerator for the MongoDB C# driver — register once and every inserted document gets a sequential Guid ID |
On modern .NET the hot paths are zero-allocation — byte buffers use stackalloc and Span<T>, and conversion methods are annotated with [SkipLocalsInit]. A BenchmarkDotNet project is included under util/Benchmarks so you can verify on your own hardware:
cd util/Benchmarks
dotnet run -c Release -- --filter *Generation*Upgrading from the legacy SequentialGuidGenerator / SequentialSqlGuidGenerator API is straightforward — replace the obsolete singleton calls with the new static methods:
| Before (legacy) | After |
|---|---|
SequentialGuidGenerator.Instance.NewGuid() |
GuidV8Time.NewGuid() |
SequentialSqlGuidGenerator.Instance.NewSqlGuid() |
GuidV8Time.NewSqlGuid() |
The legacy classes are still available (marked [Obsolete]) so your code will continue to compile, but you should migrate at your convenience.
The new RFC 9562 algorithm is fully backwards compatible with previously generated Guids:
- Sort order is preserved — All UUIDs generated with the legacy algorithm will sort before any UUIDs generated with the new algorithm in the database, so existing data ordering is unaffected.
- Timestamp extraction still works — The
ToDateTime()extension method can extract timestamps from both legacy and new UUIDs, so you do not need to migrate existing data.