Feature Flags
Strategy for migrating runtime config to managed feature flags without UI drift.
Why Feature Flags Here
Use feature flags when you need runtime control without redeploying:
- progressive rollout of behavior
- emergency disable switches
- environment-specific behavior without config forks
- short-lived experiments with explicit ownership
Keep static config for constants that are not product behavior (timeouts, hard security defaults, protocol-level settings).
Current Runtime Flags
Managed flags are declared in src/config/flags.config.ts, seeded into
feature_flags, and exposed in Admin → Site Settings when they are wired to
application behavior.
theme-managementenable-passkey-authenable-magic-linkauth-multi-session-enabledrequire-2faauth-signup-enabledauth-api-keys-enabledorg-self-serve-creation-enabledorg-invitations-enabledenable-scim-pluginbilling-enabledbilling-enforcement-enabledtoast-duration-secondstoast-stack-limittoast-gap-pxtoast-expandtoast-positionsettings-layout-max-widthactions-as-iconsdashboard-breadcrumbs-enableddashboard-section-navigation-enabledai-components-enabledmedia-image-generation-enabledcontrol-plane-mcp-enabled
settings-layout-max-width controls the width of dashboard settings-style
surfaces, including Better Auth cards, Products & services, Authorization, and
other admin configuration panels that use the settings wrapper. Dashboard
Content catalog and library surfaces also read this value so dense working
pages can use the same width policy. Dashboard section roots, including
/dashboard, /dashboard/admin, /dashboard/content,
/dashboard/organization, /dashboard/settings, and /dashboard/test, also
inherit this policy through the shared page dashboard wrapper. It supports the
standard Tailwind max-width scale, the dashboard container width, and full.
actions-as-icons switches supported dashboard action groups between full
text buttons and compact icon buttons with tooltips, including Content
catalog actions and Yayaw Table toolbars wired to the runtime flag.
dashboard-breadcrumbs-enabled and dashboard-section-navigation-enabled
control the dashboard shell navigation chrome. Both are server-side experience
flags, seeded as enabled by default, and can be disabled independently from
Admin → Site Settings when evaluating alternate dashboard navigation patterns.
control-plane-mcp-enabled is the server-side kill switch for Codex-facing MCP
control-plane tools. It is seeded as disabled by default and should be checked
by MCP/API entry points before allowing Yayaw operations through the control
plane.
Runtime Access Pattern
The Flags SDK is the canonical declaration and discovery contract. Yayaw keeps
feature_flags as the internal site-settings provider, exposes metadata through
the Vercel Flags discovery endpoint, and can evaluate PostHog-backed keys through
the PostHog adapter when the slug is listed in POSTHOG_FLAG_KEYS.
Use getManagedFlagValues([...]) or getManagedBooleanFlagValues([...]) in
server layouts, providers, dashboard navigation, auth runtime config, and any
other hot path that needs multiple flags. Single-flag helpers are kept for narrow
compatibility paths, but repeated unit reads should not be added to request
critical code.
Client components may only consume flags whose managed definition has
exposeClient: true. Those values are loaded server-side with
loadClientRuntimeFlags(), hydrated into RuntimeFlagsProvider, and revalidated
with TanStack Query. Security, auth, authz, billing enforcement, and MCP flags
must remain server-side sources of truth.
Custom Flags
Flags that are present in feature_flags but are not declared in
MANAGED_FEATURE_FLAGS are treated as Custom Flags. The admin page generates
controls for them automatically from the stored DB value:
- booleans render as switches
- numbers render as numeric inputs
- strings render as text inputs
- objects, arrays, and null values render as JSON text areas
Custom Flags are free-form runtime values. They are only used by the
application when code explicitly calls getFlag("custom-slug") or one of the
typed DB fallback helpers with that slug.
Deprecated rollout flags such as blocks-ai-plan-v1,
blocks-ai-plan-persistence-v1, blocks-ai-plan-trigger-worker-v1,
page-ai-deep-refinement-enabled, and pages-wysiwyg-v1 are hidden from the
admin UI and removed by the seed because they no longer represent useful site
settings.
Non-Negotiable Contract: Logic + UI
Any flag that controls a feature must gate both:
- backend/plugin behavior
- user-facing UI entry points
Example: auth flags now control Better Auth plugins and visible UI cards/views. If a plugin is off but UI still renders controls, users can reach dead paths.
Priority Auth/Org Flags
Current rollout priorities:
auth-signup-enabled
- Controls sign-up availability in auth UI and auth server options.
- Replaces static toggling in auth config when running invitation-only periods.
auth-api-keys-enabled
- Controls API key plugin and API key screens.
- Useful when rolling out API access gradually by customer tier.
auth-multi-session-enabled
- Controls the Better Auth multi-session plugin, the security sessions card, and the account-switching card in account settings.
- Useful when you want a single active session model for stricter environments.
org-self-serve-creation-enabled
- Controls whether users can create organizations themselves.
- Useful for enterprise setups where organizations are provisioned centrally.
org-invitations-enabled
- Controls invitation flows for adding members.
- Allows temporarily freezing growth while keeping existing organizations usable.
What Should Stay Config/Env (Not Flags)
- crypto/secrets and provider credentials
- DB connection/runtime infra knobs
- protocol/security invariants that must not drift at runtime
- static routes, locale contracts, build config, and image optimizer config
- billing catalog data, Stripe price IDs, and plan limits
- true emergency maintenance hard switch (
MAINTENANCE_MODE)
Maintenance mode in Yayaw is intentionally env-based and middleware-driven:
MAINTENANCE_MODEMAINTENANCE_MODE_END_DATE
Implementation Pattern
- Add the managed definition in
src/config/flags.config.tswith:
- stable slug
- category
- explicit default value
- clear description
- Read through one server-side accessor:
getFlag(key)for unified PostHog-first lookup with DB fallbackgetManagedBooleanFlagValue(slug)for typed boolean gates
- Apply dual gating:
- server behavior
- UI visibility
- Add docs:
- include flag in this page and architecture notes
- explain whether it appears in Runtime settings or Custom Flags
- Validate:
- enabled and disabled states
- permission boundaries
- no dead links/routes in UI
Seed Contract
The seed creates missing managed flags and repairs name, description, and
category metadata. It does not overwrite enabled or value for existing rows,
so admin choices made in Site Settings survive deploys and reseeds.
Definition of Done for New Flags
- slug and description added in seed
- server behavior gated
- UI surface gated
- no broken routes when disabled
- docs updated
-
content/llm/llm-source.mdupdated when assistant guidance changes - generated assistant docs refreshed with
bun run docs:llm:generate - CI checks pass (
check,tsc,build, docs integrity)