APP-49Recommended
Read feature flags before the first paint
Decide feature flags on the server and send them with the first page or data load. A flagged feature then never flashes in or out. The API checks the same flag.
How to do it
Follow deploy is not release for how flags work. Evaluate them per user on the server, for example with an OpenFeature provider, and pass the results to the client. A flagged API route checks the flag too, so a hidden button is no way around it. Remove flags when they are done, as stale flags describes. Every flag the screen reads is listed in Keep every flag in one register.
Examples
Python example
@app.get("/api/session")
def session_info():
user = current_user()
return {
"user": {"id": user.id, "name": user.display_name},
"flags": {"newReports": flags.is_enabled("new-reports", user=user, default=False)},
}
TypeScript example
const session = await api.get('/api/session');
const app = createApp({ flags: session.flags });
if (session.flags.newReports) app.addRoute({ path: '/reports', load: () => import('./reports/ReportsScreen') });
How to check
A browser test loads the screen with the flag off and records every frame for one second. The flagged control never appears. A direct API call to the flagged route gets 404.
Related rules
- ENG-25 Separate deploying from releasing in Engineering
- ENG-47 Keep serving when the flag service is down in Engineering
- ARC-60 Remove flags that never change in Clean code and architecture
- ENG-45 Keep every flag in one register in Engineering
- MOB-12 Plan to fix forward in Mobile apps
- IOT-30 Keep a signed remote switch for each risky feature in Connected devices
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/app-ui/resilience/feature-flags-in-ui">Agent Wranglers web app interface playbook</a>. In code you write, add a comment next to it with the same link.