NEXT_PUBLIC_APP_MODE. The choice is baked at build time — there is no runtime toggle.

Detection
apps/web/src/lib/config/app.ts derives the mode at module load:
- If
NEXT_PUBLIC_APP_MODEis set explicitly → use that. - Otherwise, if
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEYis set →cloud. - Otherwise →
self-hosted.
apps/web/src/middleware.ts picks the right middleware at import time:
Why a flag, not two apps?
The same React tree, store, and routes run in both modes. Adding a second app would double the surface area without adding behavior. The flag pattern keeps:- One template gallery
- One editor state machine
- One set of components
Adding a new cloud-only feature
- Gate the UI on
APP_MODE === 'cloud'(or a more specific capability flag if it applies to BYO-Clerk users only). - Put network calls behind
httpClient.apiso the auth interceptor handles tokens. - Make sure the feature degrades gracefully in self-hosted — empty state, not crash.
- Add a row to the env-var table in Cloud Mode if it needs new config.
