Feature flags vs. configuration vs. environment variables
Feature flags, app configuration and environment variables all change behavior without changing code. When to use each one, with a simple decision table.
All three change how an application behaves without changing its code, so teams often mix them up. They answer different questions, though, and using the wrong one leads to slow rollbacks, leaked secrets or a flag system full of things that are not flags.
Environment variables: how this deployment is wired
Environment variables describe the environment the code runs in: the database URL, the region, the API key for a payment provider, the log level.
- They are read at startup, so changing one usually means a restart or redeploy.
- They are the same for every user of that deployment.
- They are the right place for secrets, ideally injected from a secret manager.
If the value would differ between your laptop, staging and production, but never between two users, it belongs here.
Configuration: tunable values
Configuration is values the application uses: a timeout, a page size, a retry count, the list of supported currencies, the text of a banner.
- It may live in files, a database or a remote config service.
- Remote configuration can change without a deploy.
- It is usually the same for everyone, or varies by simple dimensions like region.
Feature flags: who gets which behavior, right now
A feature flag decides whether a behavior is active for a given context: this user, this account, this percentage of traffic.
- It changes at runtime, in seconds, without a deploy.
- It is evaluated per request with a context (user, plan, country).
- It usually has an end date: once the release is done, it is removed.
Decision table
| Question | Use |
|---|---|
| Is it a secret, or does it differ only by environment? | Environment variable |
| Is it a number, text or list the app needs to work? | Configuration |
| Should it be different for different users or a share of traffic? | Feature flag |
| Do you need to turn it off in seconds if something breaks? | Feature flag (a kill switch) |
| Will it still be there in two years? | Configuration or a permission flag, not a release flag |
The grey areas
Flags with values. Most flag tools support variants that are strings, numbers or JSON, not only booleans. That is useful for experiments ("which button text converts better?"), but it tempts teams to put all configuration into the flag tool. Keep a simple rule: if the value does not vary by user and does not need an instant change, it is configuration.
Permission flags. "Feature X is available on the Pro plan" can be a flag, but it is really part of your product's entitlements. If it is permanent and tied to billing, model it in your own code or database, where it is versioned and tested like everything else.
Kill switches. A kill switch for an expensive or fragile part of the system is a legitimate long-lived flag. Its whole point is being able to change it instantly, without a deploy.
Summary
Environment variables wire a deployment, configuration tunes the app, and feature flags decide who gets which behavior right now. Keeping them apart keeps secrets out of your flag tool, keeps your flag list short, and makes each change go through the right path.