Code reads feature flags through the Vercel Flags SDK, backed by the better-supabase flags module with a brand context, and brand flags are precomputed into a hidden route segment by the proxy.
CentraKit already stores feature flags in the better-supabase flags module, which decides a flag the same way in TypeScript and in database policies. System administrators could turn a flag on for one organization and set a rollout percentage, but not target a brand or a single user, and the code had no typed way to declare the flags it reads.
The app serves several brands from one deployment, and every static shell is prerendered per brand through the hidden [brand] root segment (ADR 0011). A flag that changes a static shell for one brand cannot be read with headers() or cookies without turning that shell dynamic.
The repo standard keeps apps/saas/proxy.ts to synchronous work, because it runs on every request, navigation and prefetch.
declareFlag in @workspace/core-platform/flag-declarations, which wraps flag() from flags/next with the better-supabase adapter (better-supabase/flags-sdk). A declaration carries a scope, a kind (release, ops or experiment), an owner and an expiry date.better-supabase.config.ts), so flag_evaluation and flag_enabled in SQL resolve it from the organization row.brand depend on the request host only. The proxy serializes their values for the brand into a code and inserts it as the hidden [flags] root segment after [brand], and the root layout prerenders every permutation. The group is capped at two flags, because each one doubles the prerendered shells. With no brand flags the code is __no_flags__, which needs no FLAGS_SECRET.brandFlagsCode reads an in-memory snapshot of the flag definitions that refreshes in the background after 30 seconds. Only a cold start waits on the database, for at most 150 ms, and then falls back to the declared defaults. This is the only lookup the proxy makes beyond the host and the session.request identify the signed-in user and brand from the request inside Suspense. Organization flags go through evaluateForOrganization, because the organization comes from the URL rather than the request./admin/feature-flags with list, create and detail routes, gated on platform.flag.manage. The list compares stored flags with the declarations, so a flag that is declared but missing or stored but no longer in code stands out.apps/saas/app moved one level down, to app/[locale]/[brand]/[flags]/. Typed route keys, tests and docs changed with it.FLAGS_SECRET in every Vercel environment, because the code is then signed.flagsProviderData once an endpoint exposes them.Last updated on