Splitting the NetEscapades.EnumGenerators Packages: The Road to a Stable Release
If you've been following the development of NetEscapades.EnumGenerators, you'll know it's been one of the more popular Roslyn source generator packages in the .NET ecosystem. What started as a focused tool for generating high-performance enum extension methods has grown considerably — and with that growth came architectural pressure that demanded a rethink.
In this post, I'll walk through the recent decision to split the package into multiple components, why a metapackage approach made the most sense, and what this means for the road to a stable 1.0 release.
Why the Split Was Necessary
Source generators in .NET have a unique packaging challenge. The generator itself — the assembly that runs at compile time inside the Roslyn compiler — has very different requirements from the attributes and types that your application code references at runtime.
Historically, NetEscapades.EnumGenerators bundled everything into a single NuGet package. This worked well initially, but as the library matured, several pain points emerged:
- Framework targeting conflicts: The source generator must target
netstandard2.0to work inside the compiler, while the marker attributes and runtime helpers benefit from multi-targeting acrossnet6.0,net7.0,net8.0, and beyond. - Dependency isolation: Source generators are notoriously sensitive to dependency conflicts. Bundling runtime code alongside the analyzer assembly increased the surface area for version collisions.
- Scenario flexibility: Some users wanted the attributes in a shared library without pulling in the generator. Others needed the generator in a specific project but wanted to reference the attributes from a different package.
These aren't theoretical problems — they're real issues reported by the community over time.
The New Package Architecture
The solution follows a pattern that's becoming increasingly common in the source generator ecosystem. The package is now split into three distinct components:
1. NetEscapades.EnumGenerators.Attributes
This package contains the marker attributes like [EnumExtensions] that you apply to your enum types. It has no dependency on Roslyn and can be referenced from any project in your solution, including shared class libraries.
2. NetEscapades.EnumGenerators.Generator
This package contains the actual Roslyn incremental source generator. It's packaged as an analyzer (using the analyzers/ folder convention in NuGet) and only runs at compile time. It references no runtime assemblies and keeps its dependency footprint minimal.
3. NetEscapades.EnumGenerators (Metapackage)
The original package name is now a metapackage — it contains no code of its own, but instead pulls in both the Attributes and Generator packages. This means existing users who upgrade will see zero breaking changes. Their <PackageReference> stays the same, and everything works as before.
Why a Metapackage?
The metapackage approach is the key design decision here. It provides:
- Backwards compatibility: Existing consumers don't need to change anything.
- Discoverability: New users find and install the same package name they've always seen in blog posts and documentation.
- Flexibility for advanced users: Teams with more complex project structures can reference the individual packages directly when they need fine-grained control.
This is the same pattern Microsoft uses with packages like Microsoft.Extensions.Hosting — a high-level package that composes smaller, focused packages underneath.
What This Means for the 1.0 Release
This restructuring was a prerequisite for reaching a stable release. With the packages properly separated, the API surface of each component is clearer, versioning is more predictable, and the generator can evolve independently of the attribute contracts.
The 1.0 milestone also includes:
- Incremental generator optimizations to minimize IDE impact during editing
- Improved interceptor support for the latest .NET 9 patterns
- Stable public API with proper
[PublicAPI]annotations and semantic versioning guarantees
Upgrading
For most users, upgrading is seamless — just update the NetEscapades.EnumGenerators package version. If you want to take advantage of the split, you can replace the single reference with the individual packages:
<!-- In your shared library -->
<PackageReference Include="NetEscapades.EnumGenerators.Attributes" Version="1.0.0" />
<!-- In your application project -->
<PackageReference Include="NetEscapades.EnumGenerators.Generator" Version="1.0.0" />
Final Thoughts
Package architecture might not be the most glamorous topic, but getting it right is crucial for long-term maintainability — both for library authors and consumers. The split into focused packages with a metapackage facade gives NetEscapades.EnumGenerators a solid foundation for its 1.0 release and beyond.
If you're building your own source generators, I'd strongly recommend adopting this pattern early. Your future self — and your users — will thank you.



