Skip to content
stateless.co · Engineering notes from the request/response layer
statelessThe engineering desk

A publication about the machinery under everyday software: the contracts between services, the queries behind a page, and the failures that only show up in production.

06Engineering Practice

The Smallest Feature Flag Service You Can Build Yourself

You would rightly think that a feature flag system is mainly a dashboard. a vendor or standards definition stating which part is foundational But the key architecture boundary lies…

The Smallest Feature Flag Service You Can Build Yourself
Photo: Fabartus · CC BY-SA 3.0 · Wikimedia Commons
What is in this piece
  1. Split the Control Plane from the Data Plane
  2. Roll Out Stably, Not Randomly
  3. Define a Safe Fallback Value
  4. Audit Every Change
  5. Lifecycle and Removal of Experimental Flags
  6. Vendor's Power Points
but build only what really counts: server-side evaluation, deterministic rollout, a fallback in failures, and an audited change history. Those core elements serve the full feature management lifecycle, including turning off or removing temporary flags once a feature is proven to work.

Split the Control Plane from the Data Plane

an architecture diagram showing the evaluation in the serving path The dashboard and flag storage are the control plane, where human decision-makers change the flags. But evaluation — loading a flag and delivering the right code for that user — is the critical data plane, where the decision happens. And the deciding logic must sit in the service fetching the flag, not the console.

Evaluate flags in your service, using a lightweight SDK embedded by your automated deployment, with the flag state locally. That local SDK needs to stream updates so changes disseminate in seconds. an architecture diagram showing how the SDK streams updates You also need a central flag management API, for the release manager to change a flag state.

Roll Out Stably, Not Randomly

an architectural diagram or formula showing a deterministic rollout through hashing Percentage rollout is not just a roller ball on a console; it is an engineering architecture. To be safe, rollout must be deterministic, giving the same result for the same user every time.

So rollouts are not random — they must be stable. Hash the user ID into a stable bucket for any given flag variation, so the same user gets the same flag value each time. checksum or math formula giving stable hashing of user ID to flag variation With consistent hashing, you are effectively running two clusters, not one: one live cluster with flag A and one flag B cluster.

Configure an "audience" in the console to refer to a group of users in this way. screenshot or illustration of audience configuration Define the audience with targeting keys: attributes of that user group like their country, our product tier, or segment of the database such as the top 10% by purchases.

Define a Safe Fallback Value

Just as you must be deterministic, you cannot be optimistic. You cannot assume the flags store is always there. You must define a fallback, or default, value to deliver whenever the config store is down. official code or documentation stating safe fallbacks for when config is down

So when the service fetches flag A, and the config store is unavailable, flag A is automatically delivered as if on "stable" (the fallback). docs confirming what the "stable" value means

Audit Every Change

For safety and accountability, every feature flag change must earn an audit trail. official changelog or standards doc saying flag changes must be audited The audit log should capture the new value, the targeting rule, the release manager's account, and the timestamp. a complete audit log template

This audit is as essential as the code logs for human errors. an official log system where flag changes appear And because the control plane fields matter as much as the values, the audit should capture the targeting key for all targeting rules.

Lifecycle and Removal of Experimental Flags

Each feature flag traces a lifecycle governed by the release manager. The leading flags roll out carefully, and incremental ones from experiments vanishing after their test.

To ensure release flags improve the product, the flag should continue only while it is still an experiment — not after official guide listing the exact flag stages. illustration showing the necessary flag stages After full rollout, a release flag should trigger deprecation, after which the flag can be removed by code refactor. official project fact about flags in closed works

official listing of the support SDLC from GitLab In some projects, these stage names are fixed, with flags moving through Dev, Test, Staging, Production, and Closed. Each named stage becomes a milestone on the flag's audit log.

Experimental flags are often removed after 30 days, when they have ceased to matter. data showing what fraction of flags live longer than 1.5 months Release flags may stay put but get updated during maintenance windows. So the action choice of "Add Flag" in the console must also lead to the choice of "Remove Flag".

Vendor's Power Points

You may not need to buy a vendor even with A/B experiments. The smallest service includes an event emitter sending details of every flag evaluation to a destination you own. list of primary event fields for A/B test

But the A/B charting and statistical analysis requiring expression events comes from sources emphasizing the subscription cost. mailing list or article showing the argument against buy-it-yourself for A/B stats

Also, a vendor will give you a federated flag management system and your cloud's active directory. service whose console integrates with Active Directory or Azure AD So the global corporation may need global flag management with flags stretching across its teams, adoption of standards on user privacy, and compliance with overlapping regulations.

For all that, a vendor can grow heavier than a flag service should. The bare smallest service is service-side evaluation, stable rollout, a fallback, an audit log, and removal from the codebase, leaving your serving path free.