EnumCraft.FeatureFlags 1.0.1

dotnet add package EnumCraft.FeatureFlags --version 1.0.1
                    
NuGet\Install-Package EnumCraft.FeatureFlags -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="EnumCraft.FeatureFlags" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EnumCraft.FeatureFlags" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="EnumCraft.FeatureFlags" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add EnumCraft.FeatureFlags --version 1.0.1
                    
#r "nuget: EnumCraft.FeatureFlags, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package EnumCraft.FeatureFlags@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=EnumCraft.FeatureFlags&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=EnumCraft.FeatureFlags&version=1.0.1
                    
Install as a Cake Tool

EnumCraft.FeatureFlags

Strongly-typed, provider-based feature flags built on EnumCraft.Core.

NuGet License: MIT


Overview

EnumCraft.FeatureFlags provides a clean, extensible feature flag abstraction for .NET applications. Define your own strongly-typed flag catalog, plug in a data provider, and get type-safe flag resolution with per-tenant override support.

This package is part of the EnumCraft ecosystem:

Package Description
EnumCraft.Core Strongly-typed enums and flags (TypedEnum, TypedFlag)
EnumCraft.Json JSON serialization extensions for TypedEnum and TypedFlag
EnumCraft.FeatureFlags Feature flag abstraction and resolution engine (this package)
EnumCraft.FeatureFlags.Json JSON file provider

Installation

dotnet add package EnumCraft.FeatureFlags
dotnet add package EnumCraft.FeatureFlags.Json

Requirements

  • .NET Standard 2.0+ or .NET 8.0+
  • EnumCraft.Core

Quick Start

1. Define your flag type

Each application defines its own concrete flag type. Each type has its own isolated provider, snapshot, and catalog.

using EnumCraft.FeatureFlags;

public sealed class AppFeatureFlag : FeatureFlag<AppFeatureFlag>
{
  public static readonly AppFeatureFlag DarkMode = new( Guid.Parse("6255cf3c-2a18-4082-87f0-764bf76cc0f9"),
                                                        "Dark Mode",
                                                        nameof(DarkMode),
                                                        isActiveDefault: false );
  
  public static readonly AppFeatureFlag NewDashboard = new( Guid.Parse("c473d35a-c391-444b-86a7-4aac8319db4e"),
                                                            "New Dashboard",
                                                            nameof(NewDashboard),
                                                            isActiveDefault: false );
  
  public static readonly AppFeatureFlag BetaReporting = new( Guid.Parse("c74e06d8-1b6d-4614-8218-facb10da1ca6"),
                                                             "Beta Reporting",
                                                             nameof(BetaReporting),
                                                             isActiveDefault: false );
  
  public static readonly AppFeatureFlag MaintenanceMode = new( Guid.Parse("aeba8047-b728-4e5b-8d66-f74f44a4bc76"),
                                                               "Maintenance Mode",
                                                               nameof(MaintenanceMode),
                                                               isActiveDefault: false );

  private AppFeatureFlag(Guid id, string description, string code, bool isActiveDefault = false)
    : base(id, description, code, isActiveDefault) { }
}

2. Configure at startup

Use Configure() to fail fast if the provider cannot initialize, or TryConfigure() for a safe wrapper that returns false with an error message instead of throwing an exception.

using EnumCraft.FeatureFlags.Json;

var options = new JsonFeatureFlagProviderOptions { DirectoryPath = AppDomain.CurrentDomain.BaseDirectory,
                                                   FileName      = "AppFeatureFlag.json" };

// Fail-fast — throws exception if provider fails to initialize
AppFeatureFlag.Configure(new JsonFeatureFlagProvider(options));

// — or — safe wrapper
if(!AppFeatureFlag.TryConfigure(new JsonFeatureFlagProvider(options), out var error))
{
  Console.WriteLine($"Failed to configure flags: {error}");
  return;
}

Configure() may only be called once per flag type. Calling it a second time throws InvalidOperationException. Use TryConfigure() if you need to handle the already-configured case gracefully without an exception. Runtime provider swapping via Reconfigure() is not supported in v1.0.0 - a restart is required to change providers.

3. Use anywhere

// Global resolution
if(AppFeatureFlag.DarkMode.IsActive)
{
  // enabled globally
}

// Per-tenant resolution (string tenant ID)
if(AppFeatureFlag.DarkMode["tenant-123"])
{
  // enabled for this tenant
}

// Per-tenant resolution (int tenant ID)
if(AppFeatureFlag.DarkMode[1001])
{
  // enabled for this tenant
}

// Full resolution chain (for diagnostics)
var resolution = AppFeatureFlag.DarkMode.Resolve(tenantId);
foreach(var r in resolution)
{
  Console.WriteLine($"[{r.Priority}] {r.Source} → {r.Value}");
}

Resolution Order

For any flag lookup, the resolution priority is:

  1. Tenant override — per-tenant value from provider data, if present
  2. Global override — global value from provider data, if present
  3. Constructor defaultisActiveDefault parameter value

FeatureFlagResolution

Resolve() returns IReadOnlyList<FeatureFlagResolution> - one entry per resolution source that participated. Each entry exposes the following.

Property Type Description
Description string? Description of the flag
TenantID int Tenant ID used in the resolution (0 = global)
Source FeatureFlagValueSource Which source determined the value
Priority int Priority of this source (1 = highest)
Value bool The value at this source

FeatureFlagValueSource

Value Description
Tenant Value came from a per-tenant override
Global Value came from the global section
Default Value came from the constructor isActiveDefault parameter

Optional Logging

Set a logger on the flag type for diagnostic output. Falls back to NullLogger if not set.

using Microsoft.Extensions.Logging;

var logger = loggerFactory.CreateLogger<AppFeatureFlag>();
AppFeatureFlag.SetLogger(logger);

Implementing a Custom Provider

Implement IFeatureFlagProvider to load flag data from any source:

public class MyCustomProvider : IFeatureFlagProvider
{
  public event EventHandler? Changed;

  public bool Initialize(out string? error)
  {
    // load your data
    error = null;
    return true;
  }

  public FeatureFlagData GetSnapshot()
  {
    // return current data
    return new FeatureFlagData();
  }

  public void Dispose() { }
}

IFeatureFlagProvider extends IDisposable - providers own their lifecycle and must clean up any watchers, timers, or connections in Dispose().


Framework Support

Framework Supported
.NET Framework 4.7.2+
.NET Standard 2.0+
.NET 8+


License

MIT — see LICENSE for details.


Author

Randel Bjorkquist — GitHub | NuGet

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on EnumCraft.FeatureFlags:

Package Downloads
EnumCraft.FeatureFlags.Json

JSON file provider for EnumCraft.FeatureFlags.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 155 4/26/2026
1.0.0 148 4/26/2026
0.3.1-preview 142 4/22/2026
0.3.0-preview 141 4/20/2026
0.2.2-preview 148 4/6/2026
0.2.1-preview 154 3/2/2026
0.2.0-preview 158 2/24/2026
0.1.4-preview 112 2/22/2026
0.1.3-preview 116 2/19/2026
0.1.2-preview 112 2/17/2026
0.1.1-preview 117 2/16/2026
0.1.0-preview 118 2/16/2026