Appearance
Flags
A flag is a named primitive whose value can change at runtime without redeploying. Two flag types ship today:
- Boolean flags —
trueorfalse. The everyday kill switch and gradual-rollout shape. - String flags — one of a small set of named variants (e.g.
"midnight","classic","high-contrast"). Used for A/B/n splits and theme switches.
Every flag carries:
- A key — unique within its project, e.g.
checkout.new-flow. - A type —
booleanorstring. - A default value — what callers get when no rule matches.
- A list of rules — checked top-to-bottom; the first match wins.
- A description (optional) — surfaced in the dashboard and in audit context.
Project scope vs. environment scope
A flag is created at the project level. Project-scope identity (key, type, description) is shared across every environment in the project. Each environment then carries its own state: the per-env list of rules and the per-env default value.
The split lets you keep the same flag definition while shipping different rollouts in dev, staging, and production. When you create a flag, every existing environment in the project is seeded with the default value and rules you supplied, atomically — no environment is ever left with a stale or missing flag.
When you create a new environment, every existing flag in the project gets a default-state row inserted automatically. The new environment evaluates as if it were the original project from request one.
Reading a flag
http
GET /api/v1/envs/{envId}/flags/{key}Returns the joined view: project-scope identity plus this environment's rules and default. The response carries an ETag you can supply on a subsequent PATCH for optimistic concurrency.
Editing a flag
Three shapes of edit, each scoped to what changes:
Project-scope metadata — PATCH /api/v1/projects/{id}/flags/{key}. Updates the description. Doesn't touch evaluation, doesn't rematerialize rulesets.
Per-environment state — PUT /api/v1/envs/{envId}/flags/{key}/state. Full-replace of (rules, defaultValue) for this environment only. Both fields are required; rules: [] is valid and means "always return the default value."
Project-scope deletion — DELETE /api/v1/projects/{id}/flags/{key}. Cascades to every environment's state in one transaction.
A typical lifecycle
- Create with
defaultValue: falseandrules: []. Ships dark to every environment. - Add a rule in
devthat returnstruefor your own user ID. Click around. Verify. - Add a percentage rollout in
staging:[{ "if": [], "value": true, "rolloutPercent": 10 }]— 10% of traffic flips totrue, sticky per user. - Increase to 50%, then 100% in
productionas confidence grows. - Default to
trueonce the rollout reaches 100% and rules are no longer needed. - Delete the flag (and the now-dead branch in the codebase).
The audit log records each step with the actor, the previous ruleset, the new ruleset, and a free-text reason.
See also
- Rules and contexts — how rules combine conditions, what context attributes are, how percentage rollouts hash for stickiness.
- Evaluation — how the evaluator runs rules and what the response looks like.
- API reference: Flags — every endpoint, request shape, response shape.