Add flags to your app
Read flags on your server and in the browser, bootstrap the first paint, and update live.
Flags read on both sides, with a dashboard toggle reaching an open page in about a second.
- 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 runs | SDK | Credential |
|---|---|---|
| Node server | @varia-bly/node | API key |
| Browser | @varia-bly/react | Client-side ID |
| Python server | variably-sdk | API key |
| Go server | github.com/varia-bly/go-sdk | API key |
| Anything else | Plain HTTP | Either |
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.
| SDK | Context |
|---|---|
@varia-bly/node, @varia-bly/react | { key: 'user-123' } |
variably-sdk (Python) | {"user_id": "user-123"} |
| Go | variably.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
| Variable | Where | Value |
|---|---|---|
VARIABLY_API_KEY | server only | From API Keys |
VARIABLY_BASE_URL | server | Your API endpoint |
NEXT_PUBLIC_VARIABLY_CLIENT_ID | browser bundle | From Settings → Project |
NEXT_PUBLIC_VARIABLY_BASE_URL | browser bundle | Your API endpoint |
Keep the API key out of anything prefixed for the browser. The client-side ID is the credential designed to be published.
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.