Stage 5 · Platform
Progressive Delivery Controllers
Feature Flag Rollouts
Coordinating OpenFeature flags, targeting rules, progressive exposure, and instant kill switches.
Flags in Progressive Delivery
Feature flags enable progressive delivery at the code level rather than the infrastructure level. While traffic-based canary routing shifts users by percentage, feature flags shift users by identity, segment, or configuration. This provides more control and faster rollback.
Feature flags complement traffic-based canary deployments. Traffic splitting catches infrastructure-level issues (latency, errors). Feature flags catch feature-level issues (wrong behavior, bad UX). Use both together for comprehensive progressive delivery.
OpenFeature Integration
import { OpenFeature } from '@openfeature/js-sdk';
import { LaunchDarklyProvider } from '@openfeature/launchdarkly';
// Initialize provider
const provider = new LaunchDarklyProvider({
sdkKey: process.env.LD_SDK_KEY,
context: {
kind: 'user',
name: 'Anonymous',
},
});
await OpenFeature.setProvider(provider);
const client = OpenFeature.getClient('my-app');
// Progressive feature flag evaluation
async function getCheckoutComponent(user: User) {
const checkoutVersion = await client.getStringValue(
'checkout-version',
'legacy',
{
targetingKey: user.id,
plan: user.plan,
country: user.country,
signupDate: user.signupDate.toISOString(),
}
);
switch (checkoutVersion) {
case 'v3':
return new CheckoutV3();
case 'v2':
return new CheckoutV2();
default:
return new LegacyCheckout();
}
}OpenFeature provides a vendor-neutral API for feature flag evaluation. The targeting context includes user attributes for segmentation. The switch statement routes to different implementations based on the flag value.
Progressive Exposure
# LaunchDarkly flag configuration
{
"kind": "flag",
"key": "new-checkout-flow",
"name": "New Checkout Flow",
"variations": {
"enabled": true,
"disabled": false
},
"targeting": {
"rules": [
{
"clauses": [{
"attribute": "internal",
"op": "equals",
"values": ["true"]
}],
"variation": "enabled"
},
{
"clauses": [{
"attribute": "beta",
"op": "equals",
"values": ["true"]
}],
"variation": "enabled"
},
{
"clauses": [],
"rollout": {
"variations": [
{"variation": "enabled", "weight": 10000},
{"variation": "disabled", "weight": 90000}
]
}
}
],
"fallback": "disabled"
}
}Progressive exposure starts with internal users, expands to beta users, then gradually rolls out to all users. The rollout weight is in thousandths (10000 = 10%). This is a phased rollout at the feature flag level.
Kill Switch Patterns
// Kill switch with fallback
async function processOrder(order: Order) {
const useNewPaymentFlow = await client.getBooleanValue(
'new-payment-flow',
false
);
if (useNewPaymentFlow) {
try {
return await newPaymentService.process(order);
} catch (error) {
// Automatic fallback on error
metrics.increment('payment.fallback.triggered');
return await legacyPaymentService.process(order);
}
}
return await legacyPaymentService.process(order);
}
// Circuit breaker pattern with flags
async function getUserRecommendations(userId: string) {
const useNewRecommendations = await client.getBooleanValue(
'new-recommendations',
false
);
if (useNewRecommendations) {
const cacheKey = 'recs:' + userId;
const cached = await cache.get(cacheKey);
if (cached) return cached;
try {
const recs = await newRecommendationEngine.get(userId);
await cache.set(cacheKey, recs, { ttl: 300 });
return recs;
} catch (error) {
// Kill switch: disable and cache for retry
await client.track('recommendation-failure', { userId });
return await legacyRecommendationEngine.get(userId);
}
}
return await legacyRecommendationEngine.get(userId);
}Kill switches provide instant rollback at the feature level. The try-catch pattern ensures graceful degradation. Circuit breaker patterns with caching prevent cascading failures. Flag tracking enables analytics on fallback usage.
Flag Metrics
- Flag evaluation rate — how often the flag is evaluated per second.
- Variation distribution — percentage of users seeing each variation.
- Error rate — how often flag evaluation fails.
- Fallback rate — how often the default value is used due to provider errors.
Cleanup
Feature flags accumulate technical debt. Every flag creates a code branch that must be tested and maintained. Clean up flags after full rollout by removing the flag check and the old code path.
Every release flag should have an expected removal date. Track flag age and alert when flags exceed their lifetime. Stale flags create confusion and increase the testing surface.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.