What Are Feature Flags
Learn what feature flags are, common use cases like canary releases and kill switches, and how to implement them in React and Node.js with code examples.
Last Friday at 4:47 PM, a team shipped a new checkout flow to 100% of their users. By Saturday morning, 312 support tickets had piled up -- the new flow had a race condition that only triggered when users had more than 3 items in their cart. The fix took 20 minutes, but the deploy pipeline took 45 minutes. For those 45 minutes, every user with 4+ items could not check out. Revenue loss: approximately $8,200.
Feature flags would have changed this story entirely. The team would have rolled the new checkout to 5% of users, caught the bug with 15 tickets instead of 312, and killed the feature in 2 seconds -- no deploy, no pipeline, no 45-minute wait. The broken experience would have lasted minutes, not hours, and affected dozens of users, not thousands.
A feature flag is a conditional check in your application whose value is controlled from outside the code -- through a dashboard, an API call, or a config service. At its most basic:
The
This is not a new idea. Facebook, Netflix, and Google have used feature flags for over a decade. What has changed is that you no longer need a $300/month enterprise platform to do it. The @luxkern/flags SDK gives you the same pattern for a fraction of that cost.
Instead of deploying to everyone at once, you roll out in stages: 1% -> 5% -> 25% -> 50% -> 100%. At each stage, you watch error rates, latency, and user feedback. If a metric degrades, you roll back to 0% instantly.
The SDK uses deterministic hashing on the user ID. User
A kill switch is a flag that starts ON and exists purely to be turned OFF in emergencies. You wrap critical functionality -- payment processing, email sending, third-party API calls -- behind a kill switch so you can disable it instantly if something goes wrong:
At 3 AM when Stripe's API is timing out and your retry loop is burning money, the on-call engineer opens the dashboard and flips one toggle. No deploy. No rollback. No waiting 45 minutes for a pipeline. Two seconds.
Enable features for specific user segments -- internal team members, beta testers, enterprise customers, or users in a specific region:
This lets your product team run a beta program without building a separate beta environment. Enterprise customers get early access to features as a perk. Your internal team dogfoods every feature before anyone else sees it.
Feature flags are the mechanism behind most A/B tests. Show variant A to one group and variant B to another, measure which performs better:
Long-lived feature branches are merge conflict factories. With feature flags, every developer commits to
Here is a production-ready React setup with the @luxkern/flags SDK:
The SDK fetches flag rules once, caches them locally, and evaluates against the cache. After the initial load, all evaluations are synchronous -- no loading spinners, no layout shifts, no visible flicker.
On the server side, you evaluate flags per-request. Here is a complete Express setup with a kill switch middleware:
The server-side SDK polls for flag changes every 30 seconds by default. When you flip a flag in the dashboard, the change propagates to all server instances within 30 seconds -- no deploy, no restart.
Here is the uncomfortable truth: feature flags rot. Every flag you create and forget to clean up becomes technical debt. A codebase with 60 stale flags has 60 dead code paths that nobody dares remove because nobody remembers what they do.
Two rules prevent this:
Rule 1: Set a cleanup date when you create the flag. Every flag in Luxkern FeatureFlags has an optional
Rule 2: Keep active flags under 15. If your team has more than 15 active flags at any time, you are creating more flags than you are cleaning up. Pause new flag creation until you remove stale ones. Most teams operate comfortably with 5-10 active flags.
Some teams use
Changing a flag without restarting the server (kill switch at 3 AM)
Rolling out to a percentage of users (canary release)
Targeting specific users or segments (beta program)
An audit log of who changed what and when (compliance)
Instant rollback (the whole point)
Feature flags are environment variables that graduated. Same on/off concept, but with dynamic evaluation, user targeting, gradual rollout, and 2-second rollback.
The market in 2026:
Luxkern FeatureFlags -- included in the Builder plan (EUR 39/month for 9 tools). React and Node.js SDKs, dashboard, targeting rules, progressive rollout. Built for indie developers and small teams.
LaunchDarkly -- enterprise-grade, starts around $300/month. Advanced targeting, experimentation, compliance features. Good fit for large organizations with strict governance requirements.
Unleash -- open-source, self-hosted. Free if you run your own infrastructure.
PostHog -- feature flags bundled with product analytics. Good fit if you also need session recordings and funnels.
For a detailed Luxkern vs LaunchDarkly comparison, read LaunchDarkly Alternative for Indie Developers 2026. For a hands-on implementation tutorial, see How to Implement Feature Flags in Node.js.
Feature flags give you the ability to ship fast and recover faster. The 312-ticket Saturday never has to happen. Try FeatureFlags free -- no credit card required.
Feature flags would have changed this story entirely. The team would have rolled the new checkout to 5% of users, caught the bug with 15 tickets instead of 312, and killed the feature in 2 seconds -- no deploy, no pipeline, no 45-minute wait. The broken experience would have lasted minutes, not hours, and affected dozens of users, not thousands.
A Feature Flag Is a Remote Kill Switch for Your Code
A feature flag is a conditional check in your application whose value is controlled from outside the code -- through a dashboard, an API call, or a config service. At its most basic:
if (flags.isEnabled("new-checkout")) {
renderNewCheckout();
} else {
renderLegacyCheckout();
}The
new-checkout flag is true or false, and you change it without deploying code. This does one fundamental thing: it separates deployment from release. You deploy code to production with the flag off. You verify nothing is broken. Then you turn the flag on for 1% of users, watch your metrics, and gradually increase to 100%. If anything goes wrong at any stage, you flip it off in 2 seconds.This is not a new idea. Facebook, Netflix, and Google have used feature flags for over a decade. What has changed is that you no longer need a $300/month enterprise platform to do it. The @luxkern/flags SDK gives you the same pattern for a fraction of that cost.
The Five Patterns That Matter
Pattern 1: Progressive Rollout (Canary Release)
Instead of deploying to everyone at once, you roll out in stages: 1% -> 5% -> 25% -> 50% -> 100%. At each stage, you watch error rates, latency, and user feedback. If a metric degrades, you roll back to 0% instantly.
The SDK uses deterministic hashing on the user ID. User
abc123 is always in the same percentage bucket, so they do not see the feature flickering between on and off across page loads. When you increase the rollout from 5% to 25%, the original 5% keep seeing the feature -- you are only adding new users to the pool.Pattern 2: Kill Switch
A kill switch is a flag that starts ON and exists purely to be turned OFF in emergencies. You wrap critical functionality -- payment processing, email sending, third-party API calls -- behind a kill switch so you can disable it instantly if something goes wrong:
// Kill switch: default ON, turn OFF in emergency
if (flags.isEnabled("stripe-payments")) {
await processPayment(order);
} else {
await queueForLater(order);
showBanner("Payments are temporarily delayed. Your order is saved and will process shortly.");
}At 3 AM when Stripe's API is timing out and your retry loop is burning money, the on-call engineer opens the dashboard and flips one toggle. No deploy. No rollback. No waiting 45 minutes for a pipeline. Two seconds.
Pattern 3: User Targeting
Enable features for specific user segments -- internal team members, beta testers, enterprise customers, or users in a specific region:
// Targeting rules (configured in dashboard):
// - email ends with @yourcompany.com -> always ON (internal dogfooding)
// - plan === "enterprise" -> always ON
// - country === "DE" -> 50% rollout (testing in Germany first)
// - everyone else -> OFF
const showNewDashboard = await flags.evaluate("redesigned-dashboard", {
userId: user.id,
email: user.email,
plan: user.plan,
country: user.country,
});This lets your product team run a beta program without building a separate beta environment. Enterprise customers get early access to features as a perk. Your internal team dogfoods every feature before anyone else sees it.
Pattern 4: A/B Testing
Feature flags are the mechanism behind most A/B tests. Show variant A to one group and variant B to another, measure which performs better:
const variant = await flags.evaluate("pricing-layout", { userId: user.id });
// variant.value is "control", "annual-first", or "monthly-first"
analytics.track("pricing-page-view", { variant: variant.value });Pattern 5: Trunk-Based Development
Long-lived feature branches are merge conflict factories. With feature flags, every developer commits to
main daily. Incomplete features are wrapped in flags set to OFF. No branch divergence, no multi-day merge sessions, no "big bang" integration risk. The code is always in production, always deployable -- just not visible to users until the flag is turned on.React Implementation: Complete Working Example
Here is a production-ready React setup with the @luxkern/flags SDK:
// src/flags.js -- SDK initialization
import { LuxkernFlags } from "@luxkern/flags/react";
export const flagsClient = new LuxkernFlags({
apiKey: process.env.REACT_APP_LUXKERN_FLAGS_KEY,
cacheTTL: 60_000, // cache flag evaluations for 60 seconds
});
// src/App.jsx -- Provider wraps your app
import { FlagsProvider } from "@luxkern/flags/react";
import { flagsClient } from "./flags";
function App({ user }) {
return (
<FlagsProvider
client={flagsClient}
context={{
userId: user.id,
email: user.email,
plan: user.plan,
country: user.country,
}}
>
<Dashboard />
</FlagsProvider>
);
}
// src/pages/Dashboard.jsx -- Using flags in components
import { useFlag, useVariant } from "@luxkern/flags/react";
export function Dashboard() {
const showNewSidebar = useFlag("new-sidebar");
const pricingVariant = useVariant("pricing-experiment");
return (
<div className="dashboard">
{showNewSidebar ? <NewSidebar /> : <LegacySidebar />}
<main>
{pricingVariant === "annual-first" && <AnnualFirstPricing />}
{pricingVariant === "monthly-first" && <MonthlyFirstPricing />}
{pricingVariant === "control" && <DefaultPricing />}
</main>
</div>
);
}
// src/components/FeatureGate.jsx -- Reusable gate component
import { useFlag } from "@luxkern/flags/react";
export function FeatureGate({ flag, fallback = null, children }) {
const isEnabled = useFlag(flag);
return isEnabled ? children : fallback;
}
// Usage:
// <FeatureGate flag="beta-export" fallback={<UpgradeBanner />}>
// <ExportButton />
// </FeatureGate>The SDK fetches flag rules once, caches them locally, and evaluates against the cache. After the initial load, all evaluations are synchronous -- no loading spinners, no layout shifts, no visible flicker.
Node.js Implementation: Express Middleware
On the server side, you evaluate flags per-request. Here is a complete Express setup with a kill switch middleware:
// server.js -- Feature flags in Express
const express = require("express");
const { LuxkernFlags } = require("@luxkern/flags");
const app = express();
app.use(express.json());
const flags = new LuxkernFlags({
apiKey: process.env.LUXKERN_FLAGS_API_KEY,
pollingInterval: 30_000, // poll for flag changes every 30s
});
// Middleware: attach flag evaluation to every request
app.use(async (req, res, next) => {
const user = req.user || {};
req.flags = {
isEnabled: (key) =>
flags.evaluate(key, {
userId: user.id,
email: user.email,
plan: user.plan,
}).then((r) => r.enabled),
getVariant: (key) =>
flags.evaluate(key, {
userId: user.id,
email: user.email,
plan: user.plan,
}).then((r) => r.value),
};
next();
});
// Kill switch for payment processing
app.use("/api/payments", async (req, res, next) => {
const enabled = await req.flags.isEnabled("stripe-payments");
if (!enabled) {
return res.status(503).json({
error: "Payment processing temporarily unavailable",
retry_after: 300,
});
}
next();
});
// Feature-gated endpoint
app.get("/api/search", async (req, res) => {
const useV2 = await req.flags.isEnabled("search-v2");
const results = useV2
? await searchV2(req.query.q)
: await searchV1(req.query.q);
res.json({ results, version: useV2 ? "v2" : "v1" });
});
// Progressive rollout for new pricing
app.post("/api/calculate-price", async (req, res) => {
const variant = await req.flags.getVariant("pricing-algorithm");
let price;
switch (variant) {
case "dynamic":
price = await calculateDynamic(req.body);
break;
case "tiered":
price = await calculateTiered(req.body);
break;
default:
price = await calculateLegacy(req.body);
}
res.json({ price, variant });
});
app.listen(3000, () => console.log("Running on :3000"));The server-side SDK polls for flag changes every 30 seconds by default. When you flip a flag in the dashboard, the change propagates to all server instances within 30 seconds -- no deploy, no restart.
The Flag Debt Problem (and How to Solve It)
Here is the uncomfortable truth: feature flags rot. Every flag you create and forget to clean up becomes technical debt. A codebase with 60 stale flags has 60 dead code paths that nobody dares remove because nobody remembers what they do.
Two rules prevent this:
Rule 1: Set a cleanup date when you create the flag. Every flag in Luxkern FeatureFlags has an optional
expires_at field. When a flag has been at 100% rollout for more than 30 days, the dashboard shows a warning. After 60 days, it sends a Slack notification to the flag creator. This creates social pressure to clean up.Rule 2: Keep active flags under 15. If your team has more than 15 active flags at any time, you are creating more flags than you are cleaning up. Pause new flag creation until you remove stale ones. Most teams operate comfortably with 5-10 active flags.
Feature Flags vs Environment Variables
Some teams use
FEATURE_X=true in their .env file. This works for exactly one scenario: a boolean toggle that never needs to change without a deploy. The moment you need any of the following, environment variables fall apart:Feature flags are environment variables that graduated. Same on/off concept, but with dynamic evaluation, user targeting, gradual rollout, and 2-second rollback.
Choosing a Platform
The market in 2026:
For a detailed Luxkern vs LaunchDarkly comparison, read LaunchDarkly Alternative for Indie Developers 2026. For a hands-on implementation tutorial, see How to Implement Feature Flags in Node.js.
Feature flags give you the ability to ship fast and recover faster. The 312-ticket Saturday never has to happen. Try FeatureFlags free -- no credit card required.