Skip to main content
Logo ByteAether

Announcing ByteAether.Ulid 1.3.2: .NET 10 Support and Optimized Design

We are excited to announce the release of ByteAether.Ulid version 1.3.2, which is now available on NuGet. This release introduces official support and dedicated binaries for the new .NET 10 platform, continuing our mission to provide the most performant, secure, and specification-compliant ULID (Universally Unique Lexicographically Sortable Identifier) implementation for the .NET ecosystem.

For those new to the project, ByteAether.Ulid provides a robust solution engineered to solve critical, often-overlooked issues in unique identifier generation, such as reliable overflow handling and secure monotonic generation.

Embracing .NET 10 and Finalizing C# 14 Features

The primary feature of version 1.3.2 is the inclusion of build artifacts specifically compiled against the .NET 10 SDK.

This release also solidifies our use of modern C# features. We were an early adopter of C# 14's "preview" features, specifically the field keyword. With the official release of .NET 10, we can now move from LangVersion "preview" to "latest," locking in the benefits this feature provides.

We use this feature in our GenerationOptions record to perform "fail-fast" validation. By validating a property once during its init assignment, we avoid all validation overhead on subsequent get operations or, more importantly, inside the Ulid.New() hot path.

For example, here is how we ensure that the Monotonicity property is always set to a valid enum value:

public MonotonicityOptions Monotonicity
{
	get;
	init => field = Enum.IsDefined(typeof(MonotonicityOptions), value)
		? value
		: throw new ArgumentOutOfRangeException(
			nameof(Monotonicity),
			value,
			"Invalid monotonicity option."
		);
} = MonotonicityOptions.MonotonicIncrement;

This pattern provides a critical optimization. The validation logic runs a single time when the GenerationOptions object is constructed, ensuring that any call to Ulid.New() using these options operates with pre-validated, zero-overhead configuration.

A Deeper Look: Our Multi-Targeting Strategy

Our NuGet package ships distinct, optimized artifacts for a wide range of targets:

  • .NET 10
  • .NET 9
  • .NET 8
  • .NET 7
  • .NET 6
  • .NET 5
  • .NET Standard 2.1
  • .NET Standard 2.0

This multi-targeting strategy is fundamental to our performance promise. We avoid the "lowest common denominator" approach of only shipping a .NET Standard 2.0 assembly.

When you install ByteAether.Ulid in a .NET 10 project, NuGet automatically selects the .NET 10 binary. This binary is compiled with all the latest JIT intrinsics and BCL improvements. Our codebase is rich with conditional compilation, allowing us to use the most powerful APIs available on each platform.

For example, our parsing (Ulid.Parse()) and stringification (ulid.ToString()) routines use optimized ReadOnlySpan<T> and MemoryMarshal APIs on modern targets, often leveraging SIMD for Base32 operations. This is a primary reason for our benchmark-leading performance, and it's an advantage you would lose if you only consumed a .NET Standard 2.0-compiled library.

How This Philosophy Shapes Our Core Features

This focus on performance and robust design is directly applied to the library's core features, particularly in how we handle security and reliability.

Reliable Overflow Handling

A critical, and often ignored, problem in ULID generation is the OverflowException that can occur during rapid-fire generation (many IDs in the same millisecond). While the 80-bit random component is massive, its starting value is random. This means a newly generated ULID could, by chance, have a random component already near its maximum value.

In this scenario, even a few increments (especially multi-byte random increments) could cause it to overflow. Our library programmatically prevents this by intelligently incrementing the 48-bit timestamp component by 1ms when an overflow is imminent, ensuring continuous, error-free generation.

We've written a detailed analysis of this problem and our solution here: Prioritizing Reliability: When Milliseconds Aren't Enough

Secure and Configurable Generation

The GenerationOptions class, which benefits from the field keyword mentioned earlier, is the key to our advanced security and performance tuning.

It allows you to configure MonotonicityOptions (e.g., MonotonicRandom1Byte) to defeat enumeration attacks, a vulnerability in simple +1 incrementors. It also lets you control the IRandomProvider used for both the initial random bytes and the monotonic increments. This design provides a nuanced balance, allowing for a fast, non-blocking pseudo-random incrementor while using a cryptographically secure generator for the initial seed.

You can read a deep dive into these options and their security implications here: ByteAether.Ulid v1.3.0: Enhanced ULID Generation Control and Security

Conclusion

The 1.3.2 release of ByteAether.Ulid, with its .NET 10 support, continues our commitment to providing a ULID implementation that is fast, secure, and meticulously spec-compliant.

Our aggressive multi-targeting strategy ensures your application uses the most optimized code for its platform, and our forward-looking adoption of C# features allows us to build a cleaner, faster, and more reliable API.

We encourage all architects and senior engineers who value performance, security, and specification-compliance to adopt ByteAether.Ulid for their identifier generation needs.

Latest posts in the ByteAether.Ulid series

Announcing ByteAether.Ulid 1.3.2: .NET 10 Support and Optimized Design
14 November 2025
ByteAether.Ulid v1.3.0: Enhanced ULID Generation Control and Security
31 July 2025
Prioritizing Reliability When Milliseconds Aren't Enough
19 June 2025