Skip to content

Flags and kinds

A flag is a named decision your app asks FortressFlag to make: should this device see the new checkout? Which caption goes on the buy button? How many retries before we give up? This page gives you the vocabulary the rest of the docs build on.

Flags live in a project, and have a value per environment

Section titled “Flags live in a project, and have a value per environment”

Every flag belongs to a project and is identified by its key — a short lowercase name like new-checkout. The key is what your code asks for, and it’s immutable after creation: your shipped apps have the key baked into their code, so renaming it would break them. You can change a flag’s display name any time; the key is forever.

A flag doesn’t have one value — it has a value per environment. new-checkout can be on in dev, rolling out in staging, and off in production, all at once. You toggle and target each environment independently.

Every flag has a kind, chosen at creation and immutable after it:

Kind Values Good for
Boolean true / false Kill switches, feature gates, rollouts
String Named text variants Copy experiments, algorithm selection, themes
Number Named numeric variants Limits, timeouts, thresholds

The kind is immutable for the same reason the key is: your code reads the flag through a typed call (isEnabled, stringValue, numberValue), and a flag that changed kind under a shipped app would stop making sense to it.

String and number flags serve variants — named values like control"buy-now" and treatment"start-free". The names are for you and your dashboard; your users’ devices only ever receive the value. Variant names never leave the management plane.

Defaults, and the default behind the default

Section titled “Defaults, and the default behind the default”

Two different things are called a default, and it’s worth keeping them apart:

  • The flag’s default is what an environment serves when no targeting rule matches. For a boolean flag that’s its on/off state; for a multivariate flag it’s the variant you pick as default.
  • Your code’s default is the value you pass at the call site — isEnabled("new-checkout", default: false). This is the bottom of the fallback chain: it’s what your app uses when it has never reached FortressFlag, or when the flag doesn’t exist (or doesn’t have a value to serve) in that environment.

A brand-new multivariate flag with no default variant chosen serves nothing — your code’s default answers until you decide. That’s deliberate: a flag you haven’t finished configuring should behave like a flag that isn’t there.

Deleting a flag is reversible — up to a point. Archiving removes it from your apps: on every online device the flag stops resolving within about a minute, and your code’s defaults take over. An archived flag can be restored intact within the retention window, or purged permanently after it. The archive list lives inside each project, beside the flags it holds.

If a flag has been sitting untouched for 90 days, the dashboard badges it as stale — a nudge to archive it, never an auto-archive. Flags you’ve forgotten are complexity your codebase is still paying for.