Plan, create, roll out, and retire feature flags without accumulating tech debt
Flag Lifecycle & Best Practices
Feature flags are powerful, but without discipline they become tech debt. This guide covers the full lifecycle of a flag — from planning through cleanup — and the conventions that keep your flag inventory manageable.
Lifecycle Stages
Every flag should move through these stages:
Plan → Create → Test → Roll Out → Monitor → Clean Up
1. Plan
Before creating a flag, decide:
- What decision does this flag control? A single flag should control a single feature or behavior change.
- What type of flag is it? (See Flag Type Selection below.)
- Who should see the feature? Define your targeting strategy upfront.
- What's the rollout plan? Will you do a progressive rollout or a hard switch?
- When will you remove it? Set a target cleanup date. Flags without an exit plan become permanent.
2. Create
Create the flag in the development environment first:
curl -X POST /api/flags \
-H "Authorization: Bearer flg_your_token" \
-H "Content-Type: application/json" \
-d '{
"key": "checkout-v2",
"name": "Checkout V2",
"description": "New streamlined checkout flow with fewer steps",
"type": "boolean",
"enabled": false,
"defaultValue": false,
"serviceId": "web-app",
"environment": "development",
"tags": ["checkout", "q1-2026"]
}'3. Test
Enable the flag in development and verify both paths (flag on and flag off). Use overrides to force specific values for specific test users.
4. Roll Out
Promote the flag through environments:
- Development — Full rollout, verify functionality
- Staging — Full rollout, run integration tests
- Production — Progressive rollout (5% → 25% → 50% → 100%)
Use progressive rollouts for production-critical features.
5. Monitor
While the flag is rolling out:
- Watch error rates and latency for the affected code path
- Check evaluation metrics for unexpected patterns
- Use flag health monitoring for automatic alerts
- Review the version history for any unexpected changes
6. Clean Up
Once the feature is fully rolled out and stable:
- Remove the flag checks from your code (always ship the "on" path)
- Delete the flag from Flaggr
- Remove any related targeting rules, overrides, and cohorts
Flag tech debt is the #1 complaint from teams adopting feature flags. Set a cleanup date when you create the flag. Use tags like q1-2026 to track cleanup targets. Review stale flags monthly.
Naming Conventions
Flag Keys
Flag keys must match the pattern ^[a-zA-Z][a-zA-Z0-9_-]*$:
- Start with a letter
- Contain only letters, numbers, hyphens, and underscores
- Use kebab-case by convention
| Pattern | Example | When to Use |
|---|---|---|
feature-name | checkout-v2 | Simple feature flag |
feature-name-variant | pricing-page-layout | A/B test or multi-variant |
ops-feature | ops-rate-limit-override | Operational control |
exp-hypothesis | exp-shorter-signup | Experiment |
Flag Names
Use human-readable names that non-engineers can understand:
- Good: "Checkout V2", "Dark Mode", "Holiday Banner"
- Bad: "feature_flag_123", "test", "new thing"
Tags
Use tags to categorize and track flags:
| Tag Pattern | Purpose |
|---|---|
q1-2026 | Cleanup target quarter |
checkout | Feature area |
experiment | Flag is part of an experiment |
ops | Operational control (not a feature rollout) |
permanent | Intentionally long-lived (entitlements, kill switches) |
Flag Type Selection
Choose the right type for your use case:
Boolean — On/Off Decisions
The most common type. Use for feature gates, kill switches, and simple rollouts.
const showNewCheckout = await client.getBooleanValue("checkout-v2", false);String — Configuration and Variants
Use for A/B tests with named variants, theme selection, or configuration values.
const theme = await client.getStringValue("app-theme", "light");
// Returns: "light", "dark", or "system"Number — Numeric Controls
Use for rate limits, thresholds, percentages, and numeric parameters.
const maxRetries = await client.getNumberValue("max-retries", 3);Object — Complex Configuration
Use for structured configuration that doesn't fit a single value. Keep objects small and well-typed.
const bannerConfig = await client.getObjectValue("promo-banner", {
text: "",
color: "blue",
dismissible: true,
});Default to boolean. Most flags are simple on/off decisions. Only use string, number, or object when boolean doesn't capture what you need.
Organizing Flags by Service
Group flags by the application that evaluates them:
| Service | Flags |
|---|---|
web-app | UI features, client-side experiments |
api | Backend behavior, rate limits, algorithm switches |
mobile-ios | iOS-specific features |
mobile-android | Android-specific features |
worker | Background job controls |
Don't create a single "all flags" service. Flags in a service share targeting context and evaluation scope.
Environment Promotion Workflow
A disciplined promotion workflow prevents accidental production changes:
development → staging → production
↓ ↓ ↓
Create Validate Progressive
& test with CI rollout
Use the export/import API to promote flag configurations between environments:
# Export from staging
curl "/api/flags/export?projectId=proj-123&environment=staging" \
-H "Authorization: Bearer flg_token" \
-o staging-flags.json
# Import to production (dry run first)
curl -X POST /api/flags/import \
-H "Authorization: Bearer flg_prod_token" \
-H "Content-Type: application/json" \
-d '{
"flags": [...],
"conflictResolution": "skip",
"dryRun": true
}'Tech Debt Management
Flag Inventory Review
Schedule a monthly review of your flag inventory:
- List all flags sorted by creation date
- Identify stale flags — flags older than their cleanup target
- Check for fully-rolled-out flags — 100% rollout for 2+ weeks means it's time to remove the code wrapper
- Archive completed experiments — Document results, then delete the flag
Warning Signs
| Signal | Action |
|---|---|
| Flag created 3+ months ago, still at 100% rollout | Remove the flag and code wrapper |
| Flag with no evaluations in 30 days | Verify it's still referenced in code; delete if not |
| Flag with 50+ targeting rules | Simplify with cohorts or split into multiple flags |
Flag with enabled: false for 2+ months | Either finish the feature or delete the flag |
Permanent Flags
Some flags are intentionally long-lived. Tag these as permanent and document why:
- Kill switches — Emergency shutoff for critical features
- Entitlements — Gate features by user plan (free vs pro vs enterprise)
- Operational controls — Rate limits, cache TTLs, algorithm parameters
- Compliance — Region-specific behavior (GDPR, data residency)
Related
- Concepts — Core data model and evaluation flow
- Progressive Rollouts — Staged deployment with safety checks
- Import/Export — Move flag configurations between environments
- Versioning — Track every change with rollback support
- Flag Health — Health monitoring and auto-remediation