Feature Flags: Progressive Delivery Without Release Branches
Feature Flags: Progressive Delivery Without Release Branches
Feature flags decouple deployment from release: code ships to production, but features turn on when you decide. This is the foundation of trunk-based development, canary releases, and instant rollback. This guide covers flag types, evaluation architecture, and the discipline that keeps flags from becoming technical debt.
Why Flags
Without flags, a release is a binary event: code is either live or not. With flags:
- Deploy anytime: merge to main daily; features stay dark until flagged on.
- Roll back instantly: flip a flag instead of reverting a deploy.
- Release gradually: roll out to 1%, then 10%, then 100%.
- Test in production: expose a feature to internal users first.
- Kill switches: disable a misbehaving integration without a deploy.
Flag Types
| Type | Lifetime | Example |
|---|---|---|
| Release flag | Days-weeks | New checkout flow |
| Experiment flag | Weeks | A/B test variant |
| Ops flag | Permanent | Kill switch for a third-party integration |
| Permission flag | Permanent | Beta access for specific users |
The lifetime matters: release flags must be removed after rollout; ops flags are permanent infrastructure.
Flag Evaluation
The simplest implementation is a config file, but production flags need remote evaluation so you can flip them without redeploying:
// flags.ts — client-side evaluation with a remote flag service
import { FlagClient } from "@acme/flag-client";
const flags = new FlagClient({
endpoint: "https://flags.acme.io",
environment: "production",
// Cache flags locally and refresh every 30s
cacheTtlMs: 30_000,
});
export async function isEnabled(
name: string,
context: FlagContext,
): Promise<boolean> {
return flags.evaluate(name, context);
}
// Usage — gate a feature behind a flag
const showCheckoutV2 = await isEnabled("checkout.v2", {
userId: req.user.id,
email: req.user.email,
});
if (showCheckoutV2) {
return renderCheckoutV2(req);
}
return renderCheckoutV1(req);
Progressive Rollout
Flags support percentage-based and targeted rollouts:
// Rollout rules — 10% of users, then 100% after 24h
{
"checkout.v2": {
"rules": [
{ "audience": { "percentage": 10 } },
{ "audience": { "users": ["internal-team@acme.io"] } }
]
}
}
Sticky bucketing matters: the same user must see the same variant across requests. Bucket by a stable identifier, not by request:
// Deterministic bucketing — same user always gets the same variant
import { createHash } from "node:crypto";
function bucket(userId: string, salt: string): number {
const hash = createHash("sha256").update(`${salt}:${userId}`).digest();
return hash.readUInt32BE(0) % 100;
}
const variant = bucket(user.id, "checkout.v2") < 10 ? "v2" : "v1";
Flag Evaluation at the Edge
For latency-sensitive paths, evaluate flags at the edge (CDN) or embed the flag state in the response:
// Server-side rendering — evaluate once, pass down
export async function renderPage(req: Request) {
const flags = await getFlagsForUser(req.user.id);
return {
html: render(flags),
// Client needs the same flags for hydration
flags: flags.toJSON(),
};
}
Flag Hygiene: The Discipline
Flags are debt if they live forever. The rules:
- Every release flag has an owner and a removal date. Track it in the flag service.
- Remove flags after rollout. A flag that stays past its rollout becomes dead code with two code paths.
- Default flags to off in code. The code should be safe if the flag service is unreachable:
// Fail closed: if the flag service is down, use the safe default
export async function isEnabled(
name: string,
context: FlagContext,
): Promise<boolean> {
try {
return await flags.evaluate(name, context);
} catch {
return false; // safe default
}
}
- Test both flag states. CI should run the test suite with flags on and off:
# Run tests with the flag on and off
FLAG_CHECKOUT_V2=true npm test
FLAG_CHECKOUT_V2=false npm test
- Audit flags quarterly. Delete flags that are fully rolled out or fully dead.
Trunk-Based Development with Flags
Flags enable the workflow: everyone merges to main, features are hidden behind flags, and releases are boring.
main ──► deploy ──► flags control visibility
▲
│ merge daily, feature dark
└── feature branch (hours, not weeks)
The rules: branches live hours, not weeks; every in-progress feature is behind a flag; the main branch is always deployable.
Common Failure Modes
- Flag spaghetti: hundreds of flags with no owner. Fix with hygiene rules and quarterly audits.
- Nested flags:
if (a && b && c)where each is a flag. The combination space explodes; test the combinations you ship. - Flags in the wrong layer: flags evaluated in the database layer leak into every query. Evaluate at the request boundary.
- No kill-switch testing: the rollback flag must be tested, or it will fail when you need it.
Implementation Checklist
- Choose a flag service (or build a thin one)
- Classify flags: release, experiment, ops, permission
- Implement deterministic bucketing by user ID
- Fail closed when the flag service is unreachable
- Test both flag states in CI
- Set owners and removal dates for release flags
- Audit and remove dead flags quarterly
- Practice a flag-based rollback in a drill
MatterAI builds frontier AI infrastructure for engineering teams — from inference-optimized models to autonomous coding agents and agentic code reviews.
Explore what we're building:
- Orbital IDE — Autonomous AI coding agent with background agents and deep codebase memory
- AI Code Reviews — Agentic pre-commit reviews across GitHub, GitLab, and Bitbucket
- Axon Models — Frontier-grade reasoning models at 70% lower inference cost
Share this Guide:
More Guides
Local LLMs in Your IDE: Connecting Ollama to Coding Agents and Autocomplete
Wire local models into VS Code, JetBrains, Cline, Continue, and Aider via the OpenAI-compatible API. Covers model routing, context budgets, tool calling with small models, and when a local model is the right choice for the job.
15 min readBuilding a Self-Hosted AI Stack: Ollama, Open WebUI, and Local RAG
Stand up a fully self-hosted AI stack on a single machine: Ollama for inference, Open WebUI as the chat interface, local embeddings for RAG, and a reverse proxy for secure access. No cloud dependency, no data leaving your network.
17 min readTop 5 Open-Source Coding Models to Run on Your Mac (2026)
The best local coding models for Apple Silicon in 2026, ranked by quality per gigabyte of unified memory. Covers qwen3-coder, devstral, gpt-oss, and more with real pull tags, sizes, and context windows.
14 min readRunning LLMs Locally: GGUF, Quantization, and Memory Planning
Learn the GGUF format, the quantization ladder from Q2 to FP16, and the exact memory math for running models on Apple Silicon and NVIDIA GPUs. Includes Ollama and llama.cpp tuning for KV cache and context.
15 min readOllama vs vLLM vs llama.cpp: Choosing the Right Local LLM Runtime
Compare the three dominant local LLM runtimes on architecture, throughput, hardware, and deployment context. Includes benchmark data, a decision framework, and a migration path from Ollama to vLLM.
16 min readContinue Reading
Local LLMs in Your IDE: Connecting Ollama to Coding Agents and Autocomplete
Wire local models into VS Code, JetBrains, Cline, Continue, and Aider via the OpenAI-compatible API. Covers model routing, context budgets, tool calling with small models, and when a local model is the right choice for the job.
15 min readBuilding a Self-Hosted AI Stack: Ollama, Open WebUI, and Local RAG
Stand up a fully self-hosted AI stack on a single machine: Ollama for inference, Open WebUI as the chat interface, local embeddings for RAG, and a reverse proxy for secure access. No cloud dependency, no data leaving your network.
17 min readTop 5 Open-Source Coding Models to Run on Your Mac (2026)
The best local coding models for Apple Silicon in 2026, ranked by quality per gigabyte of unified memory. Covers qwen3-coder, devstral, gpt-oss, and more with real pull tags, sizes, and context windows.
14 min readShip Faster. Ship Safer.
Join thousands of engineering teams using MatterAI to autonomously build, review, and deploy code with enterprise-grade precision.
