EnumCraft.FeatureFlags
0.1.2-preview
See the version list below for details.
dotnet add package EnumCraft.FeatureFlags --version 0.1.2-preview
NuGet\Install-Package EnumCraft.FeatureFlags -Version 0.1.2-preview
<PackageReference Include="EnumCraft.FeatureFlags" Version="0.1.2-preview" />
<PackageVersion Include="EnumCraft.FeatureFlags" Version="0.1.2-preview" />
<PackageReference Include="EnumCraft.FeatureFlags" />
paket add EnumCraft.FeatureFlags --version 0.1.2-preview
#r "nuget: EnumCraft.FeatureFlags, 0.1.2-preview"
#:package EnumCraft.FeatureFlags@0.1.2-preview
#addin nuget:?package=EnumCraft.FeatureFlags&version=0.1.2-preview&prerelease
#tool nuget:?package=EnumCraft.FeatureFlags&version=0.1.2-preview&prerelease
EnumCraft.FeatureFlags
Feature flag management system with tenant-specific overrides and auto-reload capabilities
What is EnumCraft.FeatureFlags?
A powerful feature flag system built on EnumCraft.Core that provides:
✅ Type-Safe Feature Flags - No magic strings, compile-time safety
✅ Tenant-Specific Overrides - Different settings per customer/tenant
✅ Three-Tier Priority System - Default → Global → Tenant
✅ Auto-Reload - Changes to config file automatically apply
✅ JSON Configuration - Simple, human-readable config files
✅ Resolution Transparency - See exactly where a flag's value comes from
Quick Start
Installation
dotnet add package EnumCraft.Core
dotnet add package EnumCraft.FeatureFlags
1. Define Your Feature Flags
using EnumCraft;
using EnumCraft.FeatureFlags;
public sealed partial class FeatureFlag : TypedEnumGuid<FeatureFlag>
{
// Define your feature flags with Guids (stable across environments)
public static readonly FeatureFlag DarkMode =
new(Guid.Parse("a1b2c3d4-e5f6-1234-5678-9abcdef01234"),
"Dark Mode UI",
nameof(DarkMode),
active: false); // Default value
public static readonly FeatureFlag AdvancedSearch =
new(Guid.Parse("b2c3d4e5-f612-3456-789a-bcdef0123456"),
"Advanced Search Features",
nameof(AdvancedSearch),
active: true);
}
2. Create Configuration File
Create FeatureFlags.json in your application directory:
{
"global": {
"DarkMode": true,
"AdvancedSearch": true
},
"tenants": {
"1001": {
"DarkMode": false,
"AdvancedSearch": true
},
"1002": {
"DarkMode": true,
"AdvancedSearch": false
}
}
}
3. Initialize at Application Startup
// In Global.asax.cs (ASP.NET) or Program.cs (.NET Core+)
FeatureFlag.Initialize();
// Optional: Configure custom path
// Add to web.config/app.config:
// <appSettings>
// <add key="FeatureFlagDataPath" value="C:\Config\" />
// </appSettings>
4. Use Feature Flags
// Global (default) value
if (FeatureFlag.DarkMode.IsActive)
{
EnableDarkMode();
}
// Tenant-specific value
int tenantId = GetCurrentTenantId();
if (FeatureFlag.DarkMode[tenantId])
{
EnableDarkMode();
}
// String tenant ID also supported
string tenantCode = "ACME-CORP";
if (FeatureFlag.AdvancedSearch[tenantCode])
{
ShowAdvancedSearch();
}
Priority System
Feature flags follow a three-tier priority system:
┌─────────────────────────┐
│ 3. Tenant Override │ ← Highest priority
│ (per-customer setting) │
└─────────────────────────┘
↓
┌─────────────────────────┐
│ 2. Global Setting │ ← Middle priority
│ (JSON configuration) │
└─────────────────────────┘
↓
┌─────────────────────────┐
│ 1. Default Value │ ← Lowest priority
│ (constructor parameter)│
└─────────────────────────┘
Example
// Definition
public static readonly FeatureFlag Export =
new(guid, "Export Feature", nameof(Export), active: false);
// ^^^^^ Default: false
// FeatureFlags.json
{
"global": {
"Export": true // Global override: true
},
"tenants": {
"2001": {
"Export": false // Tenant 2001 override: false
}
}
}
// Results:
Export.IsActive; // true (global overrides default)
Export[0]; // true (0 = global)
Export[1999]; // true (tenant 1999 uses global)
Export[2001]; // false (tenant 2001 has specific override)
Auto-Reload
Feature flags automatically reload when FeatureFlags.json changes:
// Initialize with auto-reload enabled (default)
FeatureFlag.Initialize(enableAutoReload: true);
// Edit FeatureFlags.json while app is running
// Changes apply automatically within 2 seconds (no restart needed!)
How It Works
- FileSystemWatcher monitors
FeatureFlags.jsonfor changes - Debounced reload (350ms) prevents thrashing during edits
- Polling fallback (2s) ensures reliability if watcher fails
- Thread-safe with proper locking
Resolution Transparency
Debug exactly where a flag's value comes from:
var resolutions = FeatureFlag.Export.Resolve(tenantId: 2001);
foreach (var r in resolutions)
{
Console.WriteLine($"Source: {r.Source}, Priority: {r.Priority}, Value: {r.Value}");
}
// Output:
// Source: Tenant, Priority: 1, Value: false ← Used (highest priority)
// Source: Global, Priority: 2, Value: true
// Source: Default, Priority: 3, Value: false
FeatureFlagResolution Properties
public readonly struct FeatureFlagResolution
{
public string? FeatureFlag { get; } // Flag description
public int TenantID { get; } // Tenant ID (0 = global)
public FeatureFlagValueSource Source { get; } // Default/Global/Tenant
public int Priority { get; } // 1 = highest
public bool Value { get; } // The actual value
}
Configuration
AppSettings Configuration
<configuration>
<appSettings>
<add key="FeatureFlagDataPath" value="C:\Config\" />
</appSettings>
</configuration>
If not configured, defaults to application base directory.
Initialize Options
// Basic initialization
FeatureFlag.Initialize();
// Custom file name
FeatureFlag.Initialize("MyFeatures.json");
// Disable auto-reload (manual reload only)
FeatureFlag.Initialize(enableAutoReload: false);
// Full customization
FeatureFlag.Initialize("CustomFeatures.json", enableAutoReload: true);
Custom Logging
Integrate with your logging framework:
using Microsoft.Extensions.Logging;
ILogger<FeatureFlag> logger = loggerFactory.CreateLogger<FeatureFlag>();
FeatureFlag.SetLogger(logger);
JSON Configuration Format
{
"global": {
"FeatureFlagCode1": true,
"FeatureFlagCode2": false
},
"tenants": {
"tenantId1": {
"FeatureFlagCode1": false,
"FeatureFlagCode3": true
},
"tenantId2": {
"FeatureFlagCode2": true
}
}
}
Rules
- Keys must match
Codeproperty from flag definitions - Tenant IDs can be strings or numbers (converted automatically)
- Missing flags fall back to next priority level
- Invalid JSON is ignored (logs error, uses previous valid config)
Advanced Usage
Implicit Bool Conversion
[Obsolete] // Marked obsolete - prefer explicit .IsActive
if (FeatureFlag.DarkMode) // Implicitly converts to bool
{
// Enabled
}
// Preferred:
if (FeatureFlag.DarkMode.IsActive)
{
// Enabled
}
Cleanup on Shutdown
// In Application_End (ASP.NET) or on shutdown
FeatureFlag.DisposeWatcher();
Best Practices
✅ DO
- Use Guids for IDs - stable across environments
- Use descriptive names - "Advanced Search Features" not "Feature1"
- Use nameof() for Code parameter - prevents typos
- Initialize early - in Global.asax or Program.cs
- Set default values thoughtfully - what's safest if config is missing?
❌ DON'T
- Hard-code tenant IDs in code - pass them as parameters
- Rely on auto-reload in critical paths - have sensible defaults
- Edit JSON while saving - use atomic file operations (save temp, rename)
Framework Support
| Framework | Supported |
|---|---|
| .NET Framework 4.7.2+ | ✅ |
| .NET Standard 2.0+ | ✅ |
| .NET Core 3.1+ | ✅ |
| .NET 5+ | ✅ |
| .NET 6+ | ✅ |
| .NET 7+ | ✅ |
| .NET 8+ | ✅ |
Dependencies
This package requires:
- EnumCraft.Core - Base typed enumeration system
- Microsoft.Extensions.Logging.Abstractions - Logging support
- System.Configuration.ConfigurationManager - AppSettings access
Related Packages
- EnumCraft.Core - Type-safe enumerations and flags
Documentation
For comprehensive documentation and examples:
- GitHub Repository
- API Documentation (coming soon)
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License - see LICENSE file for details
Author
| Product | Versions 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. |
-
.NETStandard 2.0
- EnumCraft.Core (>= 0.1.2-preview)
- Microsoft.Extensions.Logging.Abstractions (>= 2.1.1)
- System.Configuration.ConfigurationManager (>= 4.7.0)
- System.Text.Json (>= 4.7.2)
-
net8.0
- EnumCraft.Core (>= 0.1.2-preview)
- Microsoft.Extensions.Logging.Abstractions (>= 2.1.1)
- System.Configuration.ConfigurationManager (>= 4.7.0)
- System.Text.Json (>= 4.7.2)
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 | 176 | 4/26/2026 |
| 1.0.0 | 158 | 4/26/2026 |
| 0.3.1-preview | 154 | 4/22/2026 |
| 0.3.0-preview | 150 | 4/20/2026 |
| 0.2.2-preview | 155 | 4/6/2026 |
| 0.2.1-preview | 165 | 3/2/2026 |
| 0.2.0-preview | 167 | 2/24/2026 |
| 0.1.4-preview | 124 | 2/22/2026 |
| 0.1.3-preview | 125 | 2/19/2026 |
| 0.1.2-preview | 121 | 2/17/2026 |
| 0.1.1-preview | 127 | 2/16/2026 |
| 0.1.0-preview | 128 | 2/16/2026 |