All docs
Feature flagsAdd flags to your appcode

Add flags to your app

Read flags on your server and in the browser, bootstrap the first paint, and update live.

What you'll have

Flags read on both sides, with a dashboard toggle reaching an open page in about a second.

You'll need
  • An API key from API Keys
  • A client-side ID from Settings → Project

Pick the SDK for where your code runs, and know what the two sides are for.

Most integrations use two: one on the server, one in the browser. They do different jobs, and doing both is what gives you a correct first paint and a flag that changes on an open page.

Which SDK

Where your code runsSDKCredential
Node server@varia-bly/nodeAPI key
Browser@varia-bly/reactClient-side ID
Python servervariably-sdkAPI key
Go servergithub.com/varia-bly/go-sdkAPI key
Anything elsePlain HTTPEither

The credential column is the part to get right. An API key reaches every variA/Bly feature, so it stays on your server. A client-side ID reaches flag evaluation only and is safe in a bundle. See Introduction to feature flags for the full comparison.

Why both sides

The server resolves flags while the page is being generated, so the HTML is already correct. On its own that is enough — but the value is then fixed until the page renders again.

The browser evaluates on mount and holds a socket open, so a flag toggled in the dashboard reaches a page that is already open, in about a second, with nobody reloading anything.

Together, the server's values seed the browser's provider, so the first render is right and stays right. That seeding is called bootstrapping, and skipping it is what makes a flag-dependent component flash the wrong branch while values load.

// Server: resolve and pass down.
const snapshot = await client.allFlags({ key: '' });

return { props: { bootstrappedFlags: snapshot.values() } };
// Browser: seed the provider with them.
<VariablyProvider clientSideId={...} flags={bootstrappedFlags}>{children}</VariablyProvider>

The context field is named differently per SDK

Same idea, three spellings. It is the identity rules and user overrides match on, so pass something stable per user.

SDKContext
@varia-bly/node, @varia-bly/react{ key: 'user-123' }
variably-sdk (Python){"user_id": "user-123"}
Govariably.UserContext{UserID: "user-123"}

It is not your API key and not a gate key, which is worth saying because { key: ... } reads like either.

Environment variables

VariableWhereValue
VARIABLY_API_KEYserver onlyFrom API Keys
VARIABLY_BASE_URLserverYour API endpoint
NEXT_PUBLIC_VARIABLY_CLIENT_IDbrowser bundleFrom Settings → Project → Environments
NEXT_PUBLIC_VARIABLY_BASE_URLbrowser bundleYour API endpoint

Keep the API key out of anything prefixed for the browser. The client-side ID is the credential designed to be published.

Both credentials belong to one environment. An API key is created against one; each environment has its own client-side ID. Which environment a deployment reads is decided entirely by the credentials it holds — nothing in your code names one, and the SDKs deliberately cannot, since a caller able to name its own environment could read another's flag values.

One codebase, several environments

The same application often runs for several customers, tenants or communities, each needing its own flag values. Give each one an environment, and give each deployment that environment's credentials. No code branches on which is which.

# The deployment for one community
VARIABLY_API_KEY=vb_live_…                 # created against that environment
NEXT_PUBLIC_VARIABLY_CLIENT_ID=…           # that environment's client-side ID

# The deployment for another, same image, same flag keys
VARIABLY_API_KEY=vb_live_…                 # a different environment
NEXT_PUBLIC_VARIABLY_CLIENT_ID=…

The same checkoutRedesign is then on for one and off for the other, with one flag definition and no deploy to change either. Promoting a build between environments is a change of key, not of code.

Two things are worth getting right when you set this up.

Adopt one deployment at a time. A deployment with no Variably credentials should fall through to whatever you used before rather than failing. If your config carries a placeholder until someone generates the real key, treat the placeholder as absent — sending it earns a 401, and because an unreachable variA/Bly raises rather than returning a default, that failure surfaces wherever your flags are read.

A key cannot be moved between environments. Create another instead; they cost nothing and revoking one is cleaner than re-pointing it.

A missing flag is an error, not a default

Every SDK raises rather than returning the default you passed when a gate key does not exist. Call validateFlags at start-up with the keys your code reads, and every missing one is reported at once — before a request path reaches whichever is read first.

If a flag reads as undefined in the browser but works on the server

The browser sees only gates available to client-side SDKs. Open the gate and check that Hide from client-side SDKs is unticked.