Feature toggles don't require complex tools or infrastructure. They start with a single variable and an if statement using your existing deployment process.
This article covers a practical progression from basic on/off toggles, to audience targeting, and then to deployment-free changes, with realistic expectations at each step.
The Core Idea
Deploy code to production disabled, then enable when ready. No long-lived feature branches.
ENABLE_FEATURE = false
if ENABLE_FEATURE then
// new code
else
// existing code
end if
This keeps the main branch (your primary production branch) deployable from day one. A deployable main branch supports continuous integration, minimizes merge conflicts, and accelerates feedback—foundations of trunk-based development. See Trunk-Based Development (opens in a new tab) and Continuous Delivery (opens in a new tab) for more on these practices.
Getting Started
1. Pick the Right Feature
Start with: UI label changes, buttons, error messages
Avoid (if new to feature toggles): Database changes, business logic, cross-repo work
2. Basic Toggle Example
New homepage labels:
// components/homepage/labels.js
const ENABLE_NEW_HOMEPAGE_LABELS = false;
export const getHomepageLabels = () => {
if (ENABLE_NEW_HOMEPAGE_LABELS) {
return {
heroTitle: "Discover Your Next Adventure",
ctaButton: "Start Exploring",
feature1: "Smart Recommendations"
};
} else {
return {
heroTitle: "Welcome to Our Platform",
ctaButton: "Get Started",
feature1: "Feature One"
};
}
};Usage:
const labels = getHomepageLabels();
return <h1>{labels.heroTitle}</h1>;3. Deploy, Test, Activate
- Commit to main, deploy normally (feature off)
- Set true locally to test
- Set true and redeploy to activate
Phase 1: Config in Code
Centralize toggles and introduce audience targeting.
Structure:
src/
config/toggles.js
utils/toggle.jsconfig/toggles.js:
export const TOGGLES = {
ENABLE_NEW_HOMEPAGE_LABELS: {
enabled: false,
audiences: ['beta_users'],
percentage: 10
}
};utils/toggle.js:
import { TOGGLES } from '../config/toggles';
import { getUserAudience } from '../auth';
export const isEnabled = (featureName) => {
const feature = TOGGLES[featureName];
if (!feature) return false;
const audience = getUserAudience();
const audienceMatch = feature.audiences.includes(audience);
const percentageMatch = !audienceMatch && Math.random() < (feature.percentage / 100);
return feature.enabled && (audienceMatch || percentageMatch);
};Usage:
import { isEnabled } from '../../utils/toggle';
export const getHomepageLabels = () => {
if (isEnabled('ENABLE_NEW_HOMEPAGE_LABELS')) {
return { /* new labels */ };
}
return { /* existing labels */ };
};Phase 2: Deployment-Free Toggles
Once toggles are stable in code, move config outside the codebase to enable changes without deploys.
Option 1: Environment Variables (generally requires a restart)
ENABLE_NEW_HOMEPAGE_LABELS=true
HOMEPAGE_LABELS_AUDIENCES=beta_users
HOMEPAGE_LABELS_PERCENTAGE=10Option 2: Database Flags (no restarts required)
INSERT INTO feature_flags (name, enabled, audiences, percentage)
VALUES ('ENABLE_NEW_HOMEPAGE_LABELS', true, '["beta_users"]', 10);Cost: 2-second DB update, no restart.
Quick Start
- Add ENABLE_NEW_HOMEPAGE_LABELS = false
- Wrap labels in if
- Commit to main, deploy normally
Start with one if statement. Benefits compound quickly.