What is Feature Flag?
A feature flag is a conditional toggle that controls feature visibility in production without deploying new code.
What is a Feature Flag?
A feature flag (also called a feature toggle) is a conditional mechanism that lets you turn functionality on and off at runtime without shipping new code. Martin Fowler formalized the pattern around 2010, but Flickr and Facebook were already doing this stuff years earlier. You wrap code paths in boolean or multivariate conditions that evaluate against user attributes, environment variables, or percentage-based rules. The big idea: you can merge to main, deploy to prod, and still control who sees what. We've used flags on 50+ projects. They're non-negotiable if you're doing continuous delivery. Classic example: roll out a new checkout flow to 5% of users, watch error rates and conversion, then expand to 100%.
How it works
A feature flag is just an if statement evaluated against some config source. That can be an environment variable or a proper flag service like LaunchDarkly, Unleash, or Statsig.
Here's a minimal implementation in a Next.js API route:
// lib/flags.ts
export function isEnabled(flagName: string, userId?: string): boolean {
const flags = getFlags(); // from config, DB, or remote service
const flag = flags[flagName];
if (!flag) return false;
if (flag.type === 'boolean') return flag.enabled;
if (flag.type === 'percentage' && userId) {
// Deterministic hash so same user always gets same result
const hash = murmurhash(userId + flagName) % 100;
return hash < flag.percentage;
}
return false;
}
// app/api/checkout/route.ts
import { isEnabled } from '@/lib/flags';
export async function POST(req: Request) {
const user = await getUser(req);
if (isEnabled('new-checkout-v2', user.id)) {
return handleNewCheckout(req);
}
return handleLegacyCheckout(req);
}
The key architectural decisions:
- Evaluation location — server-side flags are safer (no client exposure), but client-side flags give you faster UI branching.
- Staleness tolerance — polling every 30s works for most apps. Real-time SSE/WebSocket updates matter for high-traffic rollouts.
- Flag lifecycle — every flag needs an owner and a planned removal date. Stale flags are tech debt.
Most flag services also support targeting rules (e.g., "enable for users in beta-testers group") and multivariate flags that return strings or JSON, not just booleans.
When to use it
Feature flags aren't free. Every flag adds a conditional branch and a cleanup obligation.
Use flags when:
- You're doing progressive rollouts (1% → 10% → 50% → 100%)
- You need a kill switch for risky features
- You're running A/B tests comparing two code paths
- Multiple teams merge to the same branch and need trunk-based development
- You want sales or support to toggle features per account
Skip flags when:
- The feature's trivial and low-risk — just ship it
- You don't have a process for cleanup (you'll end up with 200 stale toggles)
- The flag would need to wrap deeply nested logic across many files — refactor first
- You're solo on a side project with zero users
Our rule: if a rollback would require a hotfix deploy, wrap it in a flag.
Feature Flag vs alternatives
| Approach | Deployment decoupled from release? | Runtime control? | Complexity |
|---|---|---|---|
| Feature Flag | Yes | Yes — toggle without deploy | Medium — requires flag management + cleanup |
| Branch Deploy | No — separate deployment per branch | No | Low but slow rollback |
| Environment Variable | Partially — requires restart/redeploy | No (static at boot) | Low |
| A/B Testing Platform | Yes | Yes | High — needs analytics integration |
| Progressive Rollout (via flags) | Yes | Yes | Medium — feature flags are the mechanism |
A/B testing and progressive rollout are strategies that use feature flags. They're not alternatives — more like downstream patterns. Environment variables are the poor-man's feature flag. Fine for "is this staging or production" but terrible for per-user targeting.
Real-world example
On a recent e-commerce project (Next.js 14, Vercel), we ran Unleash (self-hosted, open source) to manage 23 flags across a 6-person team doing trunk-based development. When we launched a redesigned product detail page, we started at 2% of sessions. Within 4 hours, we caught a 12% increase in Cumulative Layout Shift — from 0.04 to 0.08. Still under the 0.1 "good" threshold but trending wrong. We paused the rollout, fixed the CSS issue, and resumed. Total time with broken layout in prod: under 5 hours, affecting roughly 800 sessions. Without the flag? That would've been a full deploy-fix-redeploy cycle hitting 100% of traffic.