Skip to content

Generated values reference

All types are in the Cratis.Concepts namespace of Cratis.Fundamentals.

TypeMemberMeaning
IGeneratable<TSelf> where TSelf : IGeneratable<TSelf>static abstract TSelf New()Creates a value with the type’s own strategy
IGeneratableInContext<TSelf> where TSelf : IGeneratableInContext<TSelf>static abstract TSelf New(GenerationContext context)Creates a value from the operation’s captured time and tenant

If a type implements both, callers use the context form. Neither interface dispatches to the other.

public readonly record struct GenerationContext(DateTimeOffset Now, string Tenant)

MemberValue
NowThe time the operation was received
TenantA portable tenant identifier string
const string DefaultTenant"00000000-0000-0000-0000-000000000000"

public static partial class GenerateValue. Every method uses a cryptographically secure generator.

SignatureOutput shapeRandom bitsTime-orderedLimits and exceptions
Guid Uuid()RFC 9562 version 4, RFC variant122NoNone
Guid UuidV7()RFC 9562 version 7 using the current UTC time74YesNone
Guid UuidV7(GenerationContext context)Version 7 using context.Now74YesMissingGenerationTime, GenerationTimeBeforeUnixEpoch
string Ulid()26 uppercase Crockford base32 characters; first character 0 to 780YesNone
string Ulid(GenerationContext context)Same, using context.Now80YesMissingGenerationTime, GenerationTimeBeforeUnixEpoch
string TypeId(string prefix)prefix + _ + 26 lowercase Crockford characters; only the suffix for an empty prefix74YesInvalidTypeIdPrefix
string TypeId(string prefix, GenerationContext context)Same, using context.Now74YesInvalidTypeIdPrefix, MissingGenerationTime, GenerationTimeBeforeUnixEpoch
string NanoId(int size = 21, string? alphabet = null)size characters drawn uniformly from the alphabetsize × log₂(alphabet length)NoInvalidNanoIdSize, InvalidNanoIdAlphabet
string Bytes(int count, ValueEncoding encoding = ValueEncoding.Base64Url)Encoded random bytes, no padding8 × countNoInvalidByteCount, UnknownValueEncoding

Argument limits:

  • TypeID prefix: empty, or 1 to 63 lowercase letters (a–z) and underscores, starting and ending with a letter. A null or invalid prefix throws InvalidTypeIdPrefix.
  • NanoID size: 1 to 256. The default is 21.
  • NanoID alphabet: 2 to 256 distinct printable ASCII characters (0x20 to 0x7E). Null selects the default alphabet ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-, 64 characters, so the default 21 characters carry 126 bits.
  • Bytes count: 1 to 512.
  • Context time: Now equal to default throws MissingGenerationTime; a Now before 1970-01-01T00:00:00Z throws GenerationTimeBeforeUnixEpoch.
MemberValueOutput of Bytes
Base64Url0RFC 4648 URL-safe base64 without padding; 32 bytes give 43 characters
Hex1Lowercase hexadecimal; 32 bytes give 64 characters
Base322RFC 4648 uppercase A–Z, 2–7 without padding; 20 bytes give 32 characters

An undefined enum value throws UnknownValueEncoding.

ExceptionThrown when
MissingGenerationTimeA context overload receives a default Now
GenerationTimeBeforeUnixEpochA context overload receives a Now before the Unix epoch
InvalidTypeIdPrefixThe TypeID prefix is null or breaks the prefix rule
InvalidNanoIdSizeThe size is outside 1 to 256
InvalidNanoIdAlphabetThe alphabet is outside 2 to 256 characters, not distinct, or not printable ASCII
InvalidByteCountThe count is outside 1 to 512
UnknownValueEncodingThe encoding is not a defined ValueEncoding
  • ULID and TypeID encode 128 bits as 26 base32 characters. 128 is not a multiple of 5, so two zero bits are added at the start, and the first character is 0 to 7.
  • A ULID is 48 bits of big-endian Unix milliseconds followed by 80 random bits. Its alphabet is 0123456789ABCDEFGHJKMNPQRSTVWXYZ.
  • A TypeID suffix is the 16 big-endian bytes of a UUID v7 in the lowercase alphabet 0123456789abcdefghjkmnpqrstvwxyz.
  • The first 10 characters of either encoding carry the 48-bit timestamp.
RuntimeImplementation
.NET 9 and laterDelegates to Guid.CreateVersion7 with the supplied time
.NET 8Built-in polyfill: six timestamp bytes, version 7 and RFC variant bits set, 74 bits from RandomNumberGenerator

Values from both are time-ordered but not monotonic within one millisecond. Clock adjustments can move timestamps backward.

  • Every strategy uses RandomNumberGenerator. NanoID chooses characters with RandomNumberGenerator.GetItems<char>, so each character is uniform.
  • There is no seeded Random, injectable generator, seed configuration or within-millisecond counter.
  • The helpers and the static interface calls use no reflection or dynamic code and are safe for Native AOT and trimming.
  • Targets: .NET 8, 9 and 10.