Glossary · CI/CD and DevOps
Feature flag
Also called: feature flags, feature toggle, feature toggles
Definition
A runtime switch that turns a code path on or off without a deploy, letting teams ship unfinished work dark, roll out gradually and roll back fast.
A feature flag (or feature toggle) is a condition in the code whose value comes from configuration at runtime: if the flag is on for this user or environment, take the new path, otherwise the old one. It separates deploying code from releasing a feature. Code can sit in production switched off, then be enabled for internal users, then 10% of customers, then everyone, and switched off again in seconds if something goes wrong.
Example
if (flags.isEnabled('new-checkout', { userId: user.id })) {
return renderNewCheckout(cart);
}
return renderLegacyCheckout(cart);
The flag service (a commercial product, an open-source one, or a table in your own database) decides the value per user, often by percentage or by attribute.
What it means for testing
Every flag doubles the number of possible paths through that piece of code. A tester needs to know:
- Which flag states ship together. Test the combination that will actually be live in production, not just “everything on”.
- Both sides of each active flag. The old path is still production code until the flag is removed, so regression suites must cover it.
- The switch itself. Turning the flag on or off mid-session should not corrupt data or strand a user halfway through a flow.
- Control in tests. Automated tests should set flag values explicitly, for example through a test-only API, a cookie or a config override, rather than depend on whatever the shared environment currently has. Otherwise someone flipping a flag breaks unrelated test runs, which looks exactly like flakiness.
test('new checkout shows delivery slots', async ({ page, context }) => {
await context.addCookies([
{ name: 'ff_new-checkout', value: 'on', url: 'https://staging.example.com' },
]);
await page.goto('https://staging.example.com/checkout');
await expect(page.getByRole('heading', { name: 'Choose a delivery slot' })).toBeVisible();
});
The cookie name here is an illustration; use whatever override mechanism your flag system provides.
Common mistakes
Flags that never get removed are the main long-term cost: dead branches, combinations nobody understands, and old paths that silently rot. Treat each release flag as temporary, with an owner and a removal date, and delete the losing branch and its tests once the rollout is complete.