Feature management

Why We Use Feature Management

Feature flags allow us to:

Benefit Examples
Release safely in small increments Dark launches, A/B testing, soft rollouts
Reduce branching complexity Keep all code in main, toggle at runtime
Target specific users/tenants Beta testers, internal staff, selected clients
Gradually roll out features Percentage rollouts, environment-based release
Decouple deployment from release Deploy anytime, enable when ready

Our solution supports cloud-managed defaults with in-app admin overrides, so authorised product/admin users can toggle features without Azure access.


Architecture Overview

Feature state is determined using layered precedence:

Order Source Purpose
1️⃣ Highest DB Overrides Admin toggles for environment/tenant, emergency disable
2️⃣ Default Azure App Configuration (or config files in dev) Rules & rollout (percentage, targeting, time windows)
3️⃣ Lowest Code defaults Fallback only when config missing

A custom Composite Feature Definition Provider merges these sources so the app uses the standard IFeatureManager API.


Getting Started

Install the Package

dotnet add package Synetec.FeatureManagement

Register in Program.cs

var builder = WebApplication.CreateBuilder(args);

// Load Azure App Configuration when enabled
builder.AddCentralizedAppConfiguration(); // Provided by the package

// Add Feature Management
builder.Services.AddSynetecFeatureManagement();

Run the EF migration to create the FeatureOverrides table.


Defining a Feature Flag

Each new feature must have:

Requirement Description
Name Unique identifier (PascalCase)
Owner Person/squad accountable for removal
Definition In App Config (or appsettings for dev)
Expiry/Cleanup Plan When flag & old code will be removed

Azure App Config definition example:
Key: .appconfig.featureflag/NewCheckout
Label: prod

Filters you may use:

  • AlwaysOn
  • Microsoft.Targeting
  • Microsoft.Percentage
  • Microsoft.TimeWindow

Using Feature Flags in Code

In C#

Inject IFeatureManager to provide the feature management capability in a controller, handler or service. You can also use the [FeatureGate] attribute to control usage.

if (await _featureManager.IsEnabledAsync("NewCheckout"))
{
    // New behaviour
}
else
{
    // Existing behaviour
}

Minimal API with Feature Gate

app.MapGet("/checkout", [FeatureGate("NewCheckout")] () =>
{
    return Results.Ok("New Checkout!");
});

In Angular

Load from API:

this.http.get('/api/config')
  .subscribe(cfg => this.flags = cfg.featureFlags);

Use in template:

<div *appFeature="'NewCheckout'">
  <!-- New UI -->
</div>

Updating Feature State

Scenario How to Toggle
Normal Product Rollout Update in Azure App Config
Emergency Disable Use Admin UI → DB override
Local Developer Testing appsettings.Development.json or UserSecrets
CI / Containers Env vars

Feature Lifecycle (Required Process)

1. Plan

  • Add name, owner, target users, success criteria
  • Create flag in App Config, set OFF
  • Add removal date (default: within 2 sprints after launch)

2. Develop

  • All new logic behind IFeatureManager check
  • Keep existing behaviour as fallback
  • Implement tests for ON and OFF states

3. Internal Release

  • Enable only for dev/test users (Targeting)
  • Validate functionality end-to-end

4. Limited/Beta Release

  • Enable for selected tenants or groups
  • Admin must be able to toggle via UI

5. Gradual Rollout

  • Increase exposure progressively (1% → 25% → 50% → 100%)
  • Monitor logs, error rate, feedback

6. Global Release

  • Set flag to AlwaysOn
  • Remove overrides if any

7. Cleanup (Mandatory)

Remove within 2 sprints after full release:

Remove Description
Legacy code path The code wrapped in the OFF branch
Flag definition Remove from App Config & config files
DB override rows Delete obsolete overrides
Tests for old logic Update to reflect single true path
Documentation Close related ADR/ticket

Flags must not accumulate — no “flag graveyards”.


Emergency Procedure

If a new feature causes issues in production:

  1. Admin disables via Admin UI → instant DB override
  2. If override fails → disable in Azure App Config
  3. If config unavailable → code fallback path still safe

Local Development Rules

We avoid relying on Azure during development.

Local precedence for feature values:

Priority Source
1 UserSecrets
2 appsettings.Development.json
3 Code default

Optional: to test real App Config locally

dotnet user-secrets set UseAzureAppConfig true

Developer Checklist

Before merging a feature:

  • Feature name, owner, and removal date defined
  • Flag added to App Config (OFF)
  • All new code behind feature flag
  • Unit tests cover ON and OFF branches
  • Admin UI can toggle (if needed)

Before full release:

  • Rollout plan executed (Targeting/Percentage)
  • Monitoring & success metrics reviewed

After full release:

  • Remove code behind OFF path
  • Remove flag from App Config & DB
  • Remove tests for old logic
  • Update docs/ticket closed

Reference Components (Provided by the Package)

The NuGet package includes:

  • Composite Feature Definition Provider (merges config + overrides)
  • EF override store & migration
  • Admin API helpers
  • Angular directive + config loader (optional if using Angular)
  • QuickStart sample