Feature Flags — One csv Variable, Flipped Without a Rebuild
REP can carry simple feature flags: switches that are on or off for a whole deployment. Use one csv variable that lists the flags that are on.
Declare one variable
Section titled “Declare one variable”variables: FEATURE_FLAGS: tier: public type: csv default: "" pattern: "([a-z0-9-]+(,[a-z0-9-]+)*)?" # optional: kebab-case names, no spaces description: "Flags that are on, comma-separated"Use one variable for all flags, not one per flag. Adding a flag is then a value change, not a manifest change.
With default: "", an unset REP_PUBLIC_FEATURE_FLAGS becomes an empty list, so every flag is off (see Defaults). The optional pattern rejects typos such as stray spaces or capitals at startup.
Read it with the SDK
Section titled “Read it with the SDK”import { rep } from '@rep-protocol/sdk';
const enabled = new Set( rep.get('FEATURE_FLAGS', '').split(',').map((f) => f.trim()).filter(Boolean),);
export const isOn = (flag: string) => enabled.has(flag);A flag is off unless it is named. There is no list of known flags to keep in sync and no “false” value to set.
The second argument to rep.get() covers the case with no gateway at all, such as unit tests or a plain vite dev. Behind the gateway, the manifest default already guarantees a string.
For example, a single image might serve a marketing landing page at / on its hosted deployment and redirect / straight to sign-in everywhere else:
# hosted deploymentREP_PUBLIC_FEATURE_FLAGS=landing-page# self-hosted deployment: leave it unset — every flag is offif (location.pathname === '/' && !isOn('landing-page')) location.replace('/login');Flags are public
Section titled “Flags are public”FEATURE_FLAGS is a PUBLIC variable, so its value is in the page source of every page the gateway serves.
- Never put a secret in a flag name. That includes a token, a customer name, or an unreleased product’s codename you can’t disclose.
- A flag is not access control. Hiding a button does not stop anyone calling the API behind it, so the server must still check permissions.
Guardrails judge each flag, not the list
Section titled “Guardrails judge each flag, not the list”The gateway’s guardrails check a csv value one element at a time. A long list of short flags can’t make --strict refuse to start, and an element that looks like a secret is still flagged.
Dev plugins
Section titled “Dev plugins”Flipping a flag
Section titled “Flipping a flag”You flip a flag by changing the environment, not the image:
- Restart: set
REP_PUBLIC_FEATURE_FLAGSand restart the container or roll the deployment. - Hot reload: with
--hot-reloadand--env-file, the gateway picks up edits to that file without a restart; it does not see changes to its own process environment. Pages usingrep.onChange('FEATURE_FLAGS', …)or a framework adapter update in place. See Hot Reload, the Kubernetes recipe, and the end-to-end Next.js example.
What this is not
Section titled “What this is not”A REP flag has one value per deployment, shared by every visitor. That makes it a good fit for environment differences, kill switches and staged launches. It cannot do:
- per-user or per-account targeting;
- percentage or gradual rollouts;
- A/B tests or experiments;
- an audit trail or a UI for non-engineers.
If you need any of those, use a dedicated feature-flag service. REP can still deliver that service’s public client key as a PUBLIC variable.