The flags module adds packages/flags: a few typed flags you can turn on for everyone or for a share of your users, without a vendor. It is off by default.
findplate create my-app --modules flagsDeclare a flag
Flags live in one object in packages/flags/src/index.ts. The name becomes a typed key everywhere, so a typo is a type error.
export const FLAGS = {
betaBanner: { default: false, description: "Show the beta badge in the dashboard" },
newCheckout: { default: false, description: "The redesigned checkout" },
} as constUse a flag
Server components, in web and dashboard:
import { getFlag } from "@/lib/flags"
if (await getFlag("newCheckout")) return <NewCheckout />Client components:
import { useFlag } from "@acme/orpc/flags"
const enabled = useFlag("newCheckout")Inside the api, context.flags.isOn("newCheckout", context.session?.user.id).
All three ask the api for flags.all, which answers for the signed in user when there is a session. The dashboard forwards the visitor's cookie, so a rollout is decided per user. If the api is down you get the default from code.
Flags are public: flags.all is readable without a session, so never put a secret in a flag name or description.
Where a value comes from
From strongest to weakest:
FLAGS_OVERRIDEin the env, for examplebetaBanner=on,newCheckout=25. Values areon,off,true,falseor a percentage. It beats everything, use it as a kill switch. The dashboard shows these rows as locked.- a row in the
feature_flagtable, edited on the Flags page of the dashboard (admins only) - the
defaultin code
A rollout of 25 means 25% of signed in users, picked by a stable hash of the flag and the user id, so a user keeps their answer while you raise the number. Anonymous visitors only get a flag that is at 100. Overrides from the database are cached for 5 seconds.
Env keys
FLAGS_OVERRIDE=Swap to the Vercel Flags SDK
Nothing here locks you in. To move to Flags SDK with Vercel Flags:
pnpm add flags @flags-sdk/vercelinapps/webandapps/dashboard- declare each flag with
flag({ key: "newCheckout", adapter: vercelAdapter, identify })in aflags.ts, whereidentifyreturns{ user: { id } }from the session - replace the body of
getFlaginlib/flags.tswith a call to that flag, anduseFlagwith a prop read from a server component - create the flags with
vercel flags create newCheckout --kind boolean, then drop theflagsmodule (findplate remove flags) once nothing calls it
The names stay the same, so call sites do not change.