Skip to main content

Overview

Feature flags (flags) let you change what an app does without redeploying. This guide covers how to define them, review changes before production, evaluate them safely in code, and when a flag is the wrong tool.

What a flag is for

Use a flag when you need at least one of these: A flag is temporary release control, not a permanent settings database. Plan the day you remove it when you create it.

Define

Write the flag key and type in code so every environment shares one definition. Review that file in a pull request like any other change.
Push with shipd push, then change targeting and rollouts in the dashboard per environment. See Define flags in code and Name, deprecate, and archive flags.

Review

Treat production flag changes like production code changes.
  1. Definitions in git. Flag keys, types, and defaults land in pull requests. Reviewers see what can exist before anyone turns it on.
  2. Diff in CI. Run shipd diff on pull requests so drift between the repo and shipd is visible before merge. See Sync flags in CI.
  3. Second pair of eyes on production. Require approvals for production environment changes when more than one person can ship.
  4. Raise exposure gradually. Start with a percentage rollout or a narrow targeting rule, then widen. Do not jump from 0% to 100% on an unproven path.
Approval policies cover flag environment state (enabled, rules, fallthrough). Archival and other definition changes are blocked on a protected environment instead of queuing for review — see Approvals. Prefer reviewing the plan before you publish.

Evaluate

Evaluate in process from a local snapshot. Do not put a network hop on the request path for the decision itself.
For how evaluation stays local and what happens when shipd is down, see Local evaluation.

Remove flags on purpose

A finished rollout that stays in the codebase forever is technical debt with a runtime API.
1

Finish the rollout

Serve the winning value to everyone (for a boolean, Fallthrough true, or archive the off path in code after you are sure).
2

Delete the branch in code

Keep only the shipped path. Remove isEnabled / getVariant calls and the key from client defaults. Deploy.
3

Deprecate, then archive

Keep the definition, set deprecated: true, and push so the lifecycle marker lands. After code no longer references the key, remove the definition and run shipd push --prune (or archive from the dashboard). Details: Name, deprecate, and archive flags.

When not to use a flag

Skip a flag when another tool is clearer: If you already created a flag and the feature is fully rolled out, remove the flag rather than leaving it at 100% forever.