Back to all posts
·5 min read

Safe releases with feature flags: enable, measure and roll back

In many teams, releasing a feature looks like one moment: code is merged, a build is deployed and everyone sees the new behaviour. That model can work for small, low-risk changes. For payment flows, new authorisation rules, AI-assisted recommendations or data migrations, a release is no longer a binary decision. Shipping code and exposing it to users should be different moments.

A feature flag creates that separation. The application contains new code, but behaviour is enabled by a rule. The team can observe a small user group first, disable the flag without waiting for a new build if a problem appears, and gradually expand the audience if results are positive. Flags are not security mechanisms on their own; with good targeting, measurement and lifecycle management, they reduce release risk.

Write down the problem a flag solves

Not every boolean-like setting is a feature flag. Some values are permanent product configuration: an organisation’s license limit, language preference or working hours are independent of a release. A feature flag is usually a temporary decision mechanism controlling who sees new behaviour, when and under which conditions.

Before adding a flag, keep a short decision record:

  • What user value or risk does it manage?
  • How does the application behave when it is on and off?
  • Who can change the flag?
  • Which metric defines success?
  • What is the target date for disabling or removing it?

These questions also help replace vague names such as newFeatureEnabled with names that describe intent and context, such as ai_summary_v2_rollout or new_checkout_validation.

Keep targeting explicit and stable

At first, a feature can be enabled only for team members, test tenants or a selected beta group. A percentage rollout can follow. The critical point is that the same user should not land in a different group at random on every request. A hash based on a stable user or tenant identifier keeps the experience consistent.

Targeting deserves extra care in multi-tenant products. Enabling a feature for an entire tenant rather than individual people can help teams try it together. Conversely, a sensitive change may need a particular role, plan or country condition. In every case, keep authorisation separate from rollout targeting: a flag decides visibility, not whether a person is allowed to perform an action.

If server and client reach different decisions, the interface and API can behave differently. Evaluate flags at one trusted point where possible, or propagate a clear flag context consistently to both sides.

The disabled path is product behaviour too

A flag being off is more than an if block not running. What does the user see? Is the previous behaviour preserved? Does an older client that cannot read new data fail? These questions become especially important when the data schema changes.

A common safe sequence is to deploy a schema and a format that both old and new code can read, then enable new writes for a small audience, and remove the old path after migration completes. The assumption that “turning off a flag restores everything” is false when an irreversible data transformation has happened.

A flag must not be the only protection for critical access decisions. Hiding a button in a client does not replace server-side authorisation. Even if a user bypasses a flag, the API must enforce permission and data boundaries independently.

Without measurement, rollout is only delayed release

Enabling a feature for five percent of users matters only when its effect is visible. Pick a few signals before release: error rate, latency, task-completion rate, support contacts, conversion or abandoned flows. For AI features, cost, refusal rate and safety signals can belong on the list too.

The flag name or version can appear as a bounded metric attribute, so new and old paths can be compared. Do not use high-cardinality values such as user identity as metric labels; use traces and structured logs for detailed diagnosis.

It is useful to define decision rules for rollout steps in advance. If error rate exceeds a threshold, disable the flag; if a positive signal holds for several days, expand the audience. The rules do not need perfect automation, but they reduce debate about the next action during an incident.

Make the rollback switch fast and trustworthy

A kill switch is useful only when a flag update reaches the application quickly enough. If configuration cache is too long, disabling the flag can remain ineffective for minutes. Critical flows can need a short TTL, notified cache invalidation or immediate server-side evaluation.

Rollback must account for dependencies too. If a frontend expects a new API field, disabling only the server-side flag can break the page. A rollback plan should define which versions work together and which behaviour is the safe default.

Flag changes should be auditable. Who changed which targeting rule, when and for what reason? An audit record is especially important for flags affecting price, permission, personal data or user experience.

Clean up flag debt regularly

Flags left behind make code harder to understand. Old and new paths multiply test cases and possible states. Unless a temporary rollout flag becomes permanent configuration, remove it after successful adoption.

Tracking an owner, creation date and review date for each flag makes cleanup easier. Alerts for expired flags expose unused branches and outdated targeting rules. Tests should cover both on and off paths for critical flows; testing only the enabled path creates surprises during rollback.

Feature flags are not an excuse to release carelessly. Code quality, testing, security review and migration discipline still matter. But when those foundations are present, flags split one large “enable for everyone” moment into smaller, measurable, reversible steps that respond to user impact.