V2.0 Release Notes: We Rewrote the Plumbing So You Don't Have To

We spent a lot of time on code you'll never look at, so you get to rest easy. Here's what shipped.

Microsoft's schema, served straight

The API now returns the standard Microsoft Feature Management format (feature_management.feature_flags[]), and Microsoft's own provider parses it. We deleted our custom translation layer. Fewer moving parts means fewer places for a bug to hide.

Export to appsettings.json

The Feature Flags page has a new Export button. Pick an environment and copy or download the JSON. Paste it into appsettings.json and Microsoft.FeatureManagement reads it without us. It's useful for local development. It also means leaving us is a copy-paste. Not that you would do that.

Client 2.0

Acmi.FeatureFlags.Client 2.0 is MIT licensed and targets net10.0. It's mostly new internals:

  • A background service keeps an in-memory snapshot of your flags. Flag checks read the snapshot and never wait on HTTP.
  • Refreshes send an ETag. If nothing changed, the API replies with an empty 304.
  • If a refresh fails, the last-known-good flags stay in place. Retries use exponential backoff, refreshes are never closer than 5 seconds apart, and long outages log at most one warning an hour.
  • If the API is down on a cold start, flags evaluate off and nothing throws into your request pipeline.
  • The default interval is 15 minutes. ClearCache() asks for a refresh now.

Changes reach your app on the next refresh, not instantly. Use a shorter interval for kill switches.

Percentage rollouts that stay put

We deleted our custom percentage filter and moved to Microsoft's Targeting filter. It hashes the user id with the feature name, so:

  • A user stays in or out of a rollout on every request.
  • Different flags bucket the same user differently.
  • In our tests, rollouts landed within 3 points of the target.

Anonymous traffic has no user id, so every anonymous request lands in the same bucket. Register an ITargetingContextAccessor that supplies a stable id, like a cookie or session id.

Bug fixes and small stuff

  • Custom filter parameters now arrive under their own names, exactly as they would in a plain appsettings.json. Before, they had a stray prefix.
  • When you hit your plan's flag limit, a banner tells you. Creating more flags is blocked with a clear message.
  • The app no longer depends on the client package. They share a schema, not a dependency.

Upgrading

dotnet add package Acmi.FeatureFlags.Client --version 2.0.0

Because the rollout hashing changed, users in an existing percentage rollout may be reshuffled once. Do the upgrade before your next gradual release, not in the middle of one.

Something broken? Open an issue. We'd rather hear it from you than from a stack trace at 2 a.m.