Back to CI/CD Pipeline
Q32Question 32 of 56

What a feature flag is and why it is useful

Key Concepts
  • A feature flag is a runtime switch that turns functionality on or off without a redeploy, decoupling deployment from release.
  • Flags enable testing in production by exposing a feature only to internal users or a small percentage while watching real behavior.
  • Instant rollback is the standout benefit: flipping a flag off disables a feature in seconds with no redeploy or rollback pipeline.
  • Flag types include release flags (gradual rollout), kill switches (disable under load), experiment flags (A/B tests), and permission flags (user segments).
  • Flags must be evaluated consistently per user (stable bucketing) and have a safe default so a flag-service outage does not break requests.
  • Release flags must be removed promptly after full rollout, because unmanaged flags accumulate into technical debt.

Definition

A feature flag is a runtime switch that turns functionality on or off without a redeploy, decoupling deployment from release so you can test in production, roll out gradually, and roll back instantly.
  • Feature flag – A runtime switch (boolean or richer rule) evaluated at request time that decides whether a piece of functionality is active.
  • Decoupling – The deployed binary contains both code paths; the flag selects which one runs, separating deploying code from releasing a feature.
  • Sources – Config file, environment variable, database, or a dedicated service (LaunchDarkly, Unleash, Flagsmith) for dynamic changes.
  • Types – Release flag (gradual rollout), kill switch (disable under load), experiment flag (A/B test), permission flag (user segments).
  • Key benefits – Test in production safely, gradual rollout limiting blast radius, instant rollback by flipping the flag off.

Think of a feature flag at the National Bank of India as a light switch for a new service, wired in advance but kept off. The new instant-transfer feature is already built into the app and shipped to every branch, but the switch is off so customers do not see it. The bank can flip it on just for Rajesh first, then for 10% of customers, then everyone, and if something looks wrong, flip it straight off in seconds with no need to send out a new app.

Understanding the Concepts

What is a feature flag?

At its simplest, a feature flag is a boolean read at runtime. The code checks whether the flag is enabled and takes one path or the other. The flag value comes from a source that can change without redeploying: an environment variable, a config file, a database, or a dedicated platform like LaunchDarkly or Unleash.

JAVA
package com.bank.service;

import java.math.BigDecimal;

public class TransferService {

    private final FeatureFlagClient flags;

    public TransferService(FeatureFlagClient flags) {
        this.flags = flags;
    }

    public TransferResult transfer(String fromAccount, String toAccount, BigDecimal amount) {
        if (flags.isEnabled("instant-transfer", fromAccount)) {
            // New path: instant transfer via UPI
            return executeInstantTransfer(fromAccount, toAccount, amount);
        } else {
            // Old path: standard NEFT transfer
            return executeNeftTransfer(fromAccount, toAccount, amount);
        }
    }
}

What types of feature flags exist?

Flags come in several kinds, each serving a different purpose.

  • Release flag – Gradually exposes a new feature. Remove it once the feature is fully rolled out.
  • Kill switch (operational flag) – Lets you disable an expensive or risky subsystem instantly under load.
  • Experiment flag – Drives A/B tests by splitting users into variants and measuring outcomes.
  • Permission flag – Enables a feature only for specific user segments, such as premium customers or internal beta testers.
JAVA
// Release flag: gradual rollout of instant transfer
if (flags.isEnabled("instant-transfer", userId)) { ... }

// Kill switch: disable recommendation engine under load
if (flags.isEnabled("recommendation-engine")) {
    recommendations = recommendationService.getRecommendations(userId);
} else {
    recommendations = Collections.emptyList();  // graceful degradation
}

// Experiment flag: A/B test for new loan offer page
String variant = flags.getVariant("loan-offer-redesign", userId);
if ("control".equals(variant)) {
    return oldLoanOfferPage();
} else {
    return newLoanOfferPage();
}

Why is testing in production useful?

With a flag, you can enable a feature only for internal users or a tiny percentage and observe real behavior with real data before a wide release. This catches issues that staging environments miss because they lack real traffic patterns and data volumes.

JAVA
// Enable only for internal beta testers at National Bank of India
// Flag rule: userId in ["rajesh", "priya", "pankaj"] -> enabled
// All other users -> disabled

// In LaunchDarkly or Unleash, this is a targeting rule:
// Segment: "internal-beta" -> [rajesh, priya, pankaj]
// Flag: instant-transfer -> ON for internal-beta, OFF for everyone else

How does gradual rollout work?

Increase exposure step by step while watching metrics. This limits blast radius at the feature level, much like a canary does at the deployment level.

TEXT
# Rollout plan for instant-transfer at National Bank of India:
# Week 1: 1% of users (stable per-user bucket)
# Week 2: 10% of users (watch error rate and latency)
# Week 3: 50% of users (watch business metrics)
# Week 4: 100% of users (full rollout, remove the flag)
JAVA
// Stable bucketing: hash the userId to ensure the same user
// always sees the same variant (no flickering)
public boolean isEnabled(String flagKey, String userId) {
    int bucket = Math.abs(userId.hashCode() % 100);
    int rolloutPercentage = getFlagPercentage(flagKey); // e.g., 10
    return bucket < rolloutPercentage;
}

Why is instant rollback the standout benefit?

If a feature misbehaves, flipping the flag off disables it in seconds without a redeploy or rollback pipeline. This is far faster than reverting a release.

BASH
# Traditional rollback: 5-15 minutes
kubectl rollout undo deployment/banking-api -n banking
kubectl rollout status deployment/banking-api -n banking

# Feature flag rollback: 2 seconds
curl -X PATCH https://flags.nationalbank.in/api/flags/instant-transfer \
  -H 'Authorization: Bearer $TOKEN' \
  -d '{"enabled": false}'
# Feature is disabled for all users immediately.
# No redeploy. No rollback pipeline. No downtime.

How do feature flags enable trunk-based development?

Incomplete features are merged behind a flag that is off, so the team avoids long-lived branches while keeping unfinished work invisible to users.

BASH
# Without flags: long-lived feature branch causes merge conflicts
git checkout -b feature/instant-transfer  # lives for 3 weeks
# Merging after 3 weeks: massive conflicts, risky integration

# With flags: merge to main daily behind a flag
git checkout -b add-transfer-button  # small, 1-day branch
# Code is behind: if (flags.isEnabled("instant-transfer")) { ... }
# Merge to main today. Flag is OFF, so users see nothing.
# Tomorrow: another small branch, another merge.
# When ready: flip the flag ON. No big-bang integration.

What are common mistakes? (WRONG then CORRECT)

JAVA
// WRONG: No safe default when the flag service is down
public boolean isEnabled(String flagKey) {
    return flagService.evaluate(flagKey);  // throws if service is down!
    // Result: flag service outage breaks ALL requests.
}

// CORRECT: Cache values and define a safe default
public boolean isEnabled(String flagKey) {
    try {
        return flagService.evaluate(flagKey);
    } catch (Exception e) {
        logger.warn("Flag service unavailable, using default for: " + flagKey);
        return getDefaultValue(flagKey);  // safe default: usually false (feature off)
    }
}
JAVA
// WRONG: Leaving release flags forever (technical debt)
if (flags.isEnabled("instant-transfer")) { ... }  // flag from 2 years ago
// 47 stale flags in the codebase. Nobody knows which are still needed.

// CORRECT: Remove release flags promptly after full rollout
// Maintain a flag registry with owner and expiry date.
// After full rollout, remove the flag and the old code path.

What should a senior engineer know?

In banking, flipping a flag is a production change that can alter how money moves. Flag changes must be audited, and sensitive flags should require approval. Flag evaluation must be fast (cached) and consistent per user (stable bucketing via hashing) so customers do not flicker between old and new behavior.

JAVA
// Audit log for flag changes
// 2024-01-15 10:30:00 | flag: instant-transfer | changed: OFF -> ON
// | by: rajesh | approved-by: pankaj | reason: full rollout

Visual Overview

DIAGRAM
Feature Flag Lifecycle
======================

  ┌─────────────────┐
  │  1. DEPLOY      │  Code shipped with flag OFF
  │  (flag OFF)     │  Users see nothing new
  └────────┬────────┘
           ▼
  ┌─────────────────┐
  │  2. INTERNAL    │  Flag ON for internal testers
  │  (beta test)    │  Rajesh, Priya test with real data
  └────────┬────────┘
           ▼
  ┌─────────────────┐
  │  3. GRADUAL     │  1% -> 10% -> 50% -> 100%
  │  (rollout)      │  Watch metrics at each step
  └────────┬────────┘
           ▼
  ┌─────────────────┐
  │  4. FULL        │  Flag ON for 100% of users
  │  (release)      │  Feature fully live
  └────────┬────────┘
           ▼
  ┌─────────────────┐
  │  5. CLEANUP     │  Remove the flag and old code path
  │  (remove flag)  │  Reduce technical debt
  └─────────────────┘

  At ANY step: flip flag OFF -> instant rollback (2 seconds)

Key Takeaway

A feature flag is a runtime switch that decides whether functionality is active, allowing you to turn a feature on or off without deploying new code. The flag value is read at request time from a source that can change without a redeploy, and because the deployed binary already contains both code paths, flipping the flag just selects which one runs. This decouples deploying code from releasing a feature.

The three key benefits are: testing in production safely by enabling a feature only for internal users or a small percentage, gradual rollout by increasing exposure step by step while watching metrics, and instant rollback by flipping the flag off in seconds without any redeploy. Flags also enable trunk-based development since unfinished work can be merged behind a flag that is off. At the National Bank of India, the instant-transfer feature shipped dark, was enabled first for internal testers like Rajesh, then for 10% of customers with stable per-user bucketing, then widened to everyone, and when an incident occurred, flipping the kill switch disabled it instantly.

Remember one sentence: feature flags decouple deployment from release, giving you instant rollback, gradual rollout, and safe production testing, but remove release flags promptly to avoid technical debt.

---

Share
Use ← → arrow keys to navigate