Feature Flags
We use Flagsmith to turn features on and off without deploying new code.
- Registry (
packages/feature-flags) — flag names and safe defaults in code. - Admin — flagsmith.feyenoord.com to toggle flags per environment.
- Edge Proxy — serves flags to our apps (cached, one instance per environment).
For local setup, see Docker Compose.
Architecture
| Component | Role |
|---|---|
| Flagsmith Core | Admin UI and source of truth (PRD runs in Azure with PostgreSQL). |
| Edge Proxy | feye-flagsmith-edge-proxy-{env}-ca — caches flags inside the Container App Environment. |
| API Gateway | Public /v2/flags route for native and Sanity only. |
Which app uses what
| App | Doc | How flags are loaded |
|---|---|---|
| Web (Next.js) | Client-side | Server fetches once per request; browser is hydrated (no separate flag request). |
| Native, Sanity | Client-side | App fetches via API gateway. |
| API, subgraphs, workers | Server-side | Service talks to Edge Proxy directly inside Azure. |
Add a flag
- Add an entry in
packages/feature-flags/src/flags.ts(keymust match Flagsmith, usesnake_case). Type name mustSCREAMING_SNAKE_CASE.
GOAL_REPLAY: {
key: "goal_replay",
description: "Enables the goal replay feature.",
defaultValue: true,
}- Create the same flag in the Flagsmith admin with the same
key - Use
flagsfrom@repo/feature-flagsin your app — never hardcode flag strings.
Set defaultValue to something safe when Flagsmith is unreachable (usually false for new features).
Check a flag
| Where | Package | Pattern |
|---|---|---|
| Web — server component | @repo/feature-flags + app SSR helper | See client-side |
| Web — client component | @repo/feature-flags-react | useFlag(flags.…) |
| Native | @repo/feature-flags-react-native | useFlag(flags.…) |
| Node service | @repo/feature-flags-nodejs | featureFlagsClient.isEnabled(flags.…) |
If Flagsmith is down, apps fall back to the registry defaultValue.
After you toggle a flag
- API / workers: changes can take up to ~40 seconds (proxy + in-process cache).
- Web: server components see updates on the next request; client UI may need a page reload.
- Native: reload or restart the app.