Feature Flags: Deploy Is Not Release
- date
- category
- CI/CD
- also in
- Reliability Engineering
- reading
- 1 min / 225 words
Rolling update, blue-green, and canary often still assume one thing:
new code version means new behavior
Feature flags appeared to split those two moments.
deploy code
release feature
The code can already be in production.
The feature can still be disabled.
Minimal example
The simplest flag is configuration.
apiVersion: v1
kind: ConfigMap
metadata:
name: api-config
data:
FEATURE_FAST_CHECKOUT: "false"
The application reads the value:
const fastCheckoutEnabled =
process.env.FEATURE_FAST_CHECKOUT === "true";
if (fastCheckoutEnabled) {
return newCheckout(request);
}
return oldCheckout(request);
This is primitive.
But it shows the mechanism:
same artifact
different behavior
In a real system, the flag can depend on user, tenant, region, or population percentage.
What it is really for
Feature flags give three useful things.
The first is separating deploy from release.
Code can be deployed earlier, while the feature is enabled later.
The second is a kill switch.
If a feature breaks the system, disabling a flag can be faster than rolling back a container image.
The third is progressive delivery.
The same flag can power:
internal rollout
beta rollout
rings
A/B test
gradual percentage rollout
Where the name lies
Feature flag sounds like a small switch.
In practice, it is a branch in code.
Every flag increases the number of possible states:
old path
new path
partially enabled dependencies
different user groups
A flag without a removal plan becomes permanent architecture.
After a few months, nobody knows whether the old path can be deleted.
Deploy is not release
The most important lesson is simple.
Deployment says:
new code is in the environment
Release says:
the user sees new behavior
Feature flags let you split those sentences.
That is powerful if the flag has an owner, a purpose, and a cleanup date.
Without that, a flag is technical debt with a nicer name.