Awesome
<p align="center"> <img alt="GUID+" src="https://github.com/BaerMitUmlaut/GuidPlus/raw/main/docs/img/logo-black.svg#gh-light-mode-only" /> <img alt="GUID+" src="https://github.com/BaerMitUmlaut/GuidPlus/raw/main/docs/img/logo-white.svg#gh-dark-mode-only" /> </p> <p align="center"> <a href="https://www.nuget.org/packages/GuidPlus/"><img alt="Build status" src="https://img.shields.io/nuget/v/GuidPlus?style=flat-square" /></a> <a href="https://github.com/BaerMitUmlaut/GuidPlus/actions/workflows/xunit.yml"><img alt="Build status" src="https://img.shields.io/github/workflow/status/BaerMitUmlaut/GuidPlus/xUnit?style=flat-square" /></a> <a href="https://github.com/BaerMitUmlaut/GuidPlus/blob/main/LICENSE"><img alt="MIT License" src="https://img.shields.io/github/license/BaerMitUmlaut/GuidPlus?style=flat-square" /></a> </p> <p align="center"> <b> <a href="#-about">About</a> โข <a href="#-quickstart">Quickstart</a> โข <a href="#-features">Features</a> โข <a href="#-contributing">Contributing</a> โข <a href="#-license">License</a> </b> </p>๐ก About
GUID+ is a drop-in replacement for .NET's default UUID generation, enabling generation of version 6, 7 and 8 UUIDs. These UUID versions are time-based and sequential, enabling database sharding and k-sortable IDs โ even with multiple distributed ID-generating nodes. Additionally, GUID+ is based on .NET Standard 2.0 and has zero dependencies, which makes it easy to integrate into both new and legacy projects.
๐ Quickstart
Use the following command to install GUID+ from NuGet:
dotnet add package GuidPlus
Then simply add the namespace and replace Guid
with Guid7
when you're generating new UUIDs:
+ using GuidPlus;
...
- var guid = Guid.NewGuid();
+ var guid = Guid7.NewGuid();
If you are unsure which UUID version you should use, version 7 is a safe choice.
๐ Features
GUID+ implements the draft for three new UUID versions: UUIDv6, UUIDv7 and UUIDv8. Unlike the current UUID versions, UUIDs in these new versions are k-sortable. This means that sorting a sequence of UUIDs will result in them being almost perfectly sorted by their creation time. Compared to the current UUID versions, this can increase database performance due to easier indexing and simplifies sharding databases, while still enabling the generation of IDs on multiple nodes without collisions. Additionally, it allows you to skip querying a seperate timestamp column if you need your query results sorted by time or when querying the most recently created rows.
If you want to read more details about the draft, you can find the full proposal for extending RFC4122 here:
https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-02
UUIDv6
Version 6 is based on version 1, with some small but important changes. Both versions contain a Gregorian epoch timestamp (time in 100 nanosecond intervals since 1582-08-15T00:00:00Z). However, version 1 UUIDs reorder the timestamp bits, which makes them not k-sortable. Version 6 skips the reordering, but is otherwise quite similar.
<p align="center"> <img alt="UUIDv6 layout" src="https://github.com/BaerMitUmlaut/GuidPlus/raw/main/docs/img/layout-v6-black.png#gh-light-mode-only" /> <img alt="UUIDv6 layout" src="https://github.com/BaerMitUmlaut/GuidPlus/raw/main/docs/img/layout-v6-white.png#gh-dark-mode-only" /> </p>Version 6 UUIDs end with 48 node bits which can be set by the application or randomly generated. Version 1 used the MAC address to fill these node bits, however, this is not recommended anymore.
Usage
// Random node bits
var guid = Guid6.NewGuid();
// Predefined node bits
var node = new byte[] { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
var guid = Guid6.NewGuid(node);
// Preconfigured generator
var node = new byte[] { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
var generator = new Guid6.Generator(node);
var guid = generator.NewGuid();
UUIDv7
Version 7 is most likely the UUID version you want to use. It contains a Unix timestamp (time in seconds since 1970-01-01T00:00:00Z), followed by a sub-second precision section. GUID+ uses the millisecond remainder to fill this section. The timestamp is followed by a 12 bit sequence counter. This allows you to generate up to 4096 unique IDs per millisecond per node, which should be enough for almost any application.
<p align="center"> <img alt="UUIDv7 layout" src="https://github.com/BaerMitUmlaut/GuidPlus/raw/main/docs/img/layout-v7-black.png#gh-light-mode-only" /> <img alt="UUIDv7 layout" src="https://github.com/BaerMitUmlaut/GuidPlus/raw/main/docs/img/layout-v7-white.png#gh-dark-mode-only" /> </p>Version 7 UUIDs generated by GUID+ use 62 node bits, which are by default randomly generated. When using fixed node bits, the first two bits of the first byte passed to the generator method will by overwritten with the UUID variant bits.
Usage
// Random node bits
var guid = Guid7.NewGuid();
// Predefined node bits
var node = new byte[] { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 };
var guid = Guid7.NewGuid(node);
// Preconfigured generator
var node = new byte[] { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 };
var generator = new Guid7.Generator(node);
var guid = generator.NewGuid();
UUIDv8
Version 8 UUIDs can be used for rare use cases when a different type of timestamp must be used. This could be because you have an unconventional time source or require higher precision timestamps than those used by version 7. It is likely that there will be changes to UUIDv8 in a revised version of the draft that might not be fully compatible with the current version, so it is not recommended to use version 8 UUIDs for now. However, GUID+ provides the generic implementation described in the second version of the RFC draft for the sake of completeness:
- For timestamps with a length of up to 48 bits, the first bits contain the timestamp. If the timestamp is smaller than 48 bits, the remaining bits are set to 0. The next 16 bits contain the version and sequence number and the remaining 64 bits contain 2 bits for the variant and 62 node bits.
- For timestamps with a length of up to 60 bits, the first 64 bits contain the timestamp and the version. The next 2 bits contain the variant, followed by 8 sequence bits and 54 node bits.
Due to the flexible nature of version 8 UUIDs they can only be created by using a preconfigured generator.
Usage
// Random node bits
var generator = new Guid8.Generator(() => timeSource.GetTime(), 60);
var guid = generator.NewGuid();
// Predefined node bits
var node = new byte[] { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
var generator = new Guid8.Generator(() => timeSource.GetTime(), 60, node);
var guid = generator.NewGuid();
Node Bits
All three of the new UUID variants between 48 and 62 node bits. These bits are randomly generated by default, but can be set to a fixed set of bits. When generating UUIDs with more than one instance of your application, you can use a different set of bits per instance to prevent collisions. Note that in most cases, the entropy of the randomly generated bits should already be good enough to prevent collisions.
Node bits can additionally be used to track the origin of each UUID. For example, the 62 node bits of UUIDv7 provide ample space to insert unique IDs for the datacenter, server, application and the PID of the generating node. You could also insert a short, human-readable string.
When using fixed node bits, keep in mind that public facing UUIDs will also contain these bits and might give an attacker unexpected insights into your infrastructure. Depending on what information you use to generate your node bits, you might want to use a hash instead of raw data.
Generators
GUID+ provides a generator class for each UUID version. These classes allow you to configure your node bits on application startup instead of setting them each time you generate a UUID. All UUID generators share the IGuidGenerator
interface to simplify dependency injection and avoid binding your code to a specific UUID version.
โ Contributing
All contributions are welcome. If you want to add a new or missing feature, please open an issue first to discuss a possible implementation and to track progress.
๐งพ License
GUID+ is licensed under the terms of the MIT license. You can find the full text in the LICENSE file.