← All articles
CI/CD Feature Flag Tools for Progressive Rollouts 2026-02-09 · 6 min read · feature-flags · progressive-rollout · a-b-testing

Feature Flag Tools for Progressive Rollouts

CI/CD 2026-02-09 · 6 min read feature-flags progressive-rollout a-b-testing deployment launchdarkly unleash

Feature Flag Tools for Progressive Rollouts

Feature flags decouple deployment from release. You merge code to main and deploy it to production, but the new behavior is hidden behind a flag. You turn it on for 1% of users, watch your metrics, bump to 10%, then 50%, then 100%. If something breaks, you flip the flag off -- no rollback, no revert, no hotfix deploy. This guide covers the tools that make this workflow practical.

Why Feature Flags Matter

Without feature flags, deployment and release are the same event. You ship code and everyone gets it simultaneously. If something goes wrong, your options are revert (slow, risky) or push a fix forward (slower, riskier).

Feature flags give you a kill switch and a dimmer. You control who sees what, when, without touching your deployment pipeline. This enables:

LaunchDarkly

LaunchDarkly is the market leader and the most feature-rich option. It supports every major language and framework, handles billions of evaluations daily, and has the deepest targeting and analytics capabilities.

Basic Usage

import * as ld from "@launchdarkly/node-server-sdk";

const client = ld.init("sdk-key-from-dashboard");
await client.waitForInitialization();

const context = {
  kind: "user",
  key: "user-123",
  email: "[email protected]",
  custom: { plan: "enterprise", region: "us-west" },
};

// Simple boolean flag
const showNewDashboard = await client.variation("new-dashboard", context, false);

if (showNewDashboard) {
  renderNewDashboard();
} else {
  renderOldDashboard();
}

Targeting Rules

LaunchDarkly's targeting is where it shines. You can target by user attributes, percentages, segments, and complex rule combinations -- all from the dashboard, no code changes.

# Example targeting rules (configured in dashboard)
1. If email ends with @ourcompany.com -> true (internal dogfooding)
2. If segment = "beta-testers" -> true
3. If plan = "enterprise" AND region = "us-west" -> 25% true
4. Default -> false

Strengths: Best-in-class targeting, real-time flag evaluation with streaming, excellent SDKs for every language, audit logs, approval workflows, experimentation (A/B testing), and strong compliance features.

Weaknesses: Expensive. Pricing starts around $10/seat/month for the Pro plan, and Enterprise pricing is opaque. For a small team, this can be hard to justify.

Best for: Teams that need enterprise-grade flag management with compliance, experimentation, and multi-environment support.

Unleash

Unleash is the leading open-source feature flag platform. You can self-host it for free or use their managed offering.

Self-Hosting

# Docker Compose for local development
docker compose up -d

# Or run directly with Docker
docker run -p 4242:4242 \
  -e DATABASE_URL=postgres://user:pass@db:5432/unleash \
  unleashorg/unleash-server

SDK Usage

import { initialize } from "unleash-client";

const unleash = initialize({
  url: "https://unleash.yourcompany.com/api",
  appName: "my-app",
  customHeaders: { Authorization: "your-api-token" },
});

unleash.on("ready", () => {
  const enabled = unleash.isEnabled("new-dashboard", {
    userId: "user-123",
    properties: { plan: "enterprise" },
  });
});

Activation Strategies

Unleash has built-in activation strategies that cover most use cases:

You can also define custom strategies for domain-specific targeting.

Strengths: Open source (self-hostable), good SDK coverage, built-in gradual rollout, reasonable managed pricing, active community.

Weaknesses: The dashboard UI is less polished than LaunchDarkly. Experimentation features are limited to the paid plan. Self-hosting means you manage the infrastructure.

Best for: Teams that want control over their flag infrastructure and don't need enterprise compliance features.

Flagsmith

Flagsmith is another open-source option with a slightly different philosophy. It combines feature flags with remote configuration, letting you manage both boolean flags and configuration values in one place.

import flagsmith from "flagsmith/isomorphic";

await flagsmith.init({
  environmentID: "your-env-id",
});

// Boolean flag
if (flagsmith.hasFeature("new_dashboard")) {
  renderNewDashboard();
}

// Remote config value
const maxItems = flagsmith.getValue("max_items_per_page");

Strengths: Open source, combines flags with remote config, simpler than Unleash for basic use cases, edge API for low-latency evaluation.

Weaknesses: Smaller community than Unleash, fewer activation strategies out of the box.

Best for: Teams that want both feature flags and remote configuration in a single tool.

OpenFeature: The Vendor-Neutral Standard

OpenFeature is a CNCF project that defines a standard API for feature flag evaluation. Instead of coding directly against LaunchDarkly or Unleash, you code against OpenFeature and swap providers.

import { OpenFeature } from "@openfeature/server-sdk";
import { LaunchDarklyProvider } from "@launchdarkly/openfeature-node-server";

// Configure the provider (swap this to change vendors)
await OpenFeature.setProviderAndWait(new LaunchDarklyProvider("sdk-key"));

const client = OpenFeature.getClient();
const showDashboard = await client.getBooleanValue("new-dashboard", false, {
  targetingKey: "user-123",
});

If you later switch from LaunchDarkly to Unleash, you change the provider initialization -- your application code stays the same. This is worth adopting early if you think you might switch providers or want to avoid vendor lock-in.

Rolling Your Own (When It Makes Sense)

For simple use cases, a feature flag system doesn't need to be complicated:

// Simple file-based flags
const flags = {
  "new-dashboard": {
    enabled: true,
    percentage: 25,       // 25% of users
    allowlist: ["user-1"], // always enabled for these users
  },
};

function isEnabled(flag: string, userId: string): boolean {
  const config = flags[flag];
  if (!config?.enabled) return false;
  if (config.allowlist?.includes(userId)) return true;
  // Deterministic percentage based on user ID
  const hash = hashCode(`${flag}:${userId}`);
  return (hash % 100) < config.percentage;
}

This works for small teams with simple needs. You lose the dashboard, targeting rules, audit logs, and analytics -- but you gain simplicity and zero dependencies.

Roll your own when: You have fewer than 10 flags, don't need a dashboard, and your targeting is simple (on/off or percentage-based).

Use a platform when: You have multiple teams managing flags, need audit trails, want A/B testing, or your targeting rules are complex.

Comparison

Feature LaunchDarkly Unleash Flagsmith DIY
Open Source No Yes Yes N/A
Self-Hosted No Yes Yes Yes
Targeting Excellent Good Good Basic
A/B Testing Built-in Paid Basic No
SDKs 25+ 15+ 12+ N/A
Dashboard Excellent Good Good No
OpenFeature Yes Yes Yes No
Starting Price ~$10/seat/mo Free (OSS) Free (OSS) Free

Best Practices

Name flags well. Use a consistent convention like enable-new-dashboard or experiment-checkout-flow-v2. Include the type (feature, experiment, operational) in the name.

Set expiration dates. Every flag should have a planned removal date. Flags that live forever become tech debt -- nobody remembers what they do, and nobody dares remove them. Most platforms let you set reminders or enforce cleanup.

Keep flag evaluation fast. SDKs cache flag values locally and evaluate them in-process. Don't make a network call on every evaluation. If you're rolling your own, cache aggressively.

Test both paths. Every flag creates two code paths. Write tests for both the enabled and disabled states. If you only test the enabled path, the disabled path will silently rot.

Use flags for operations, not just features. Create kill switches for expensive operations: disable real-time notifications during a traffic spike, fall back to cached data when your database is stressed, turn off non-critical background jobs during an incident.

Recommendations