All docs
Feature flagsEnvironmentsdashboard

Environments

One flag, a different answer per environment — and per tenant, if that is how you are organised.

What you'll have

Environments created, credentials scoped to them, and a clear line between what is shared and what is not.

One flag, a different answer in each environment — and a credential that decides which one you get.

An environment is a copy of every flag's state, not a copy of your flags. Create staging and each flag you already have appears there immediately, carrying whatever you tell it to carry, while the flag itself — its key, its type, its variations — stays one thing you edit once.

This is the same split LaunchDarkly makes, and worth being precise about, because it decides where each control lives.

Belongs to the flagBelongs to the environment
Gate keyEnabled
Name and descriptionDefault value
Flag type and variationsRules
Hide from client-side SDKsUser overrides

Change something in the left column and every environment sees it. Change something in the right column and only the environment you are looking at changes.

What to make an environment

The obvious answer is development, staging, production, and for a single product that is the right answer.

The more useful answer, if you run the same application for several customers, tenants or communities, is one environment per tenant. Each gets its own credentials, its own on/off state for every flag, and its own targeting — and a mistake in one cannot reach another. A team running fifty communities from one codebase gets fifty independent switchboards over one set of flag definitions.

Nothing enforces either scheme. An environment is a name and a set of values.

Creating one

Settings → Project → Environments → New environment.

Give it a key — the short string credentials resolve against, like staging or gundam — and a display name. Then the choice that matters:

Copy from an existing environment and every flag arrives with that environment's exact state: the same on/off, the same default values. Use this when the new environment should start out behaving like an existing one.

Leave it empty and every flag arrives switched off, keeping its default value. That is deliberate. A new environment that silently turned a hundred features on for a new tenant would be a bad first day.

Either way, no flag is ever missing from an environment. A flag created later is added to every environment automatically, so your code never sees a flag that exists in one place and not another.

Switching between them

The environment switcher sits on the feature flag screens — above the flag list, and on a flag's own page — not in the sidebar. Environments change flag values and nothing else, and a selector at project level would suggest it scoped prompts, evaluations and keys too. It is hidden until a project has two environments, because with one there is nothing to switch.

Everything flag-related follows it: the list's on/off controls, the values on a flag's page, which rules and overrides you see, and which environment a new rule or override is created in. If you are unsure which environment you are changing, the switcher is the answer, and the flag page repeats it — "Enabled in Staging" rather than a bare "Enabled".

The default environment

One environment per project is the default, marked in settings. It is where anything that does not name an environment ends up:

  • An API key created before environments existed
  • An API key whose environment was deleted
  • A rule or override created through the API without one

It cannot be deleted while it is the default. Promote another environment first, then delete it.

Credentials

Each environment has its own client-side ID, and each API key belongs to one environment. A credential cannot read another environment's flag values, whatever it asks for.

That is a boundary around values, not around resources. Two API keys in the same project reach exactly the same prompts, experiments and LLM features; what differs is which environment's flag state answers them. The dashboard calls the field Feature flag environment for that reason.

The environment is never taken from the request body — only from the credential. A browser cannot ask for another tenant's flags by changing a parameter.

When you create an API key you choose its environment, and it cannot be moved afterwards. Create a second key instead; they are free and revoking one is cleaner than re-pointing it.

Resetting an environment's client-side ID invalidates the old one immediately. Anything still using it stops resolving, so deploy the new value first.

Deleting one

Deleting an environment removes its flag state, its rules and its overrides. The flags themselves are untouched — they exist in every other environment exactly as before.

API keys bound to the deleted environment are not revoked. They fall back to the project default, which keeps them working but means they start reading different values. Revoke them yourself if that is not what you want.

The default environment cannot be deleted at all.

Reading a flag from a specific environment

Nothing in your code names an environment. The credential carries it, which means moving a deployment from staging to production is a change of key, not a change of code.

curl -s https://api.variably.dev/api/v1/sdk/evaluate \
  -H "X-API-Key: $VARIABLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"flag_key":"checkoutRedesign","context":{"userId":"user-123"}}'

Run that with a staging key and a production key and you get each environment's answer for the same flag and the same user. That is the whole feature.