How to declare a feature flag with the Flags SDK, choose its scope, and read it per brand, organization or user.
Code reads feature flags through the Flags SDK (flags/next), backed by the better-supabase flags module. System administrators change flags at /admin/feature-flags (admin guide). ADR 0031 records the design.
| Module | Holds |
|---|---|
@workspace/core-platform/flag-declarations | declareFlag, the declaredFlags registry, brandFlags and evaluateForOrganization. |
@workspace/core-platform/brand-flags | brandFlagsCode for the proxy, brandFlagCodes for the root layout and readBrandFlag for pages. |
@workspace/supabase-runtime/flags-sdk | The Flags SDK adapter and identify helpers from better-supabase/flags-sdk. |
Add the flag to declaredFlags in packages/core-platform/src/flag-declarations.ts:
export const newEditor = declareFlag({
description: "The block editor for templates",
expiresAt: "2027-03-01",
key: "new_editor",
kind: "release",
owner: "content",
scope: "request",
});
export const declaredFlags: readonly DeclaredFlag[] = [newEditor];A declared flag without a database row serves false, and the admin list shows it as Not configured until someone creates it. Give release and experiment flags an expiry date, so the list marks them when they are due for removal. Set expiresAt to null only for operational switches.
| Scope | Decided by | Read with |
|---|---|---|
brand | The request host only. | readBrandFlag(flag, code) with the flags root param. |
request | The signed-in user and the brand. | await newEditor.flag() inside Suspense. |
Organization flags use scope request and are read with evaluateForOrganization, because the organization comes from the URL rather than the request. Pass a user ID only when the rollout should bucket per user; without it, a whole organization falls on the same side of the rollout.
The proxy serializes the brand flags for the request host into a code and inserts it as the hidden [flags] segment, so the route tree is app/[locale]/[brand]/[flags]/. The root layout prerenders every permutation for every locale and brand.
FLAGS_SECRET in every environment, because the code is then signed. Without brand flags the code is __no_flags__./admin/feature-flags. Until then the list shows it as Not in code.Last updated on