Stage 5 · Platform
Deployment Strategies
Feature Flags
Decoupling deploy from release with LaunchDarkly, OpenFeature, targeting rules, and kill switches.
Deploy vs Release
Deploy means the code is running in production. Release means users can see and use the feature. Feature flags decouple these two concepts — you can deploy code to production without releasing it to users. This eliminates the risk of incomplete features reaching production.
With feature flags, every commit is deployable. Half-built features are deployed behind flags and activated when complete. This enables trunk-based development while maintaining the ability to ship features independently.
Feature Flag Types
| Type | Lifecycle | Example |
|---|---|---|
| Release flag | Weeks to months | New checkout flow, redesigned dashboard |
| Experiment flag | Days to weeks | A/B test button colors, pricing models |
| Ops flag | Permanent | Rate limiting, circuit breakers, maintenance mode |
| Permission flag | Permanent | Beta features, premium capabilities |
OpenFeature Standard
import { OpenFeature } from '@openfeature/js-sdk';
// Initialize with a provider (LaunchDarkly, Flipt, etc.)
const provider = new LaunchDarklyProvider({
sdkKey: process.env.LD_SDK_KEY,
});
await OpenFeature.setProvider(provider);
const client = OpenFeature.getClient('my-app');
// Check a feature flag
const showNewCheckout = await client.getBooleanValue(
'new-checkout-flow',
false,
{ targetingKey: user.id, plan: user.plan }
);
if (showNewCheckout) {
return new CheckoutComponent();
} else {
return legacyCheckout();
}OpenFeature is a vendor-neutral standard for feature flags. The same code works with LaunchDarkly, Flipt, Flagsmith, or any OpenFeature-compliant provider. This avoids vendor lock-in.
Targeting Rules
flags:
new-checkout-flow:
variations:
enabled: true
disabled: false
defaultVariation: disabled
targeting:
rules:
# Internal team gets it first
- conditions:
- attribute: email
op: endsWith
values: ["@mycompany.com"]
variation: enabled
# Beta users
- conditions:
- attribute: beta_user
op: equals
values: ["true"]
variation: enabled
# 10% rollout
- conditions:
- attribute: user_id
op: segmentMatch
values: ["checkout-rollout-10"]
variation: enabled
# Premium users
- conditions:
- attribute: plan
op: in
values: ["premium", "enterprise"]
variation: enabled
defaultRule:
percentage:
enabled: 10
disabled: 90Targeting rules allow gradual rollout by user segment, percentage, or attribute. Internal users get access first, then beta users, then a percentage rollout, then all users. This minimizes risk at each stage.
Kill Switches
# In your application
const client = OpenFeature.getClient();
async function processPayment(order) {
const useNewPaymentFlow = await client.getBooleanValue(
'new-payment-flow',
false
);
if (useNewPaymentFlow) {
try {
return await newPaymentService.charge(order);
} catch (error) {
// Kill switch: fall back to legacy flow
console.error('New payment flow failed, using legacy:', error);
return await legacyPaymentService.charge(order);
}
} else {
return await legacyPaymentService.charge(order);
}
}A kill switch instantly disables a feature by toggling the flag. The application falls back to the legacy behavior without redeployment. This is faster than rolling back a deployment and affects only the specific feature.
Flag Hygiene
- Delete flags after full rollout — once a feature is enabled for 100% of users, remove the flag and the old code path.
- Document flag purpose — every flag should have a description, owner, and expected removal date.
- Track flag age — alert when flags exceed their expected lifetime.
- Limit flag count — more flags means more code paths and more testing combinations.
Feature flags enable per-environment configuration. Set flags in your CI pipeline to enable features in staging but not production. This lets you test features in staging without affecting production users.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.