Deployment Overview
LumiBase supports two deployment modes from the same CMS codebase:
- Cloudflare Workers for the edge API runtime.
- Docker self-hosting for teams that want to operate the full stack in containers.
The public documentation site is a static Vite app deployed separately to Cloudflare Pages. The public Marketplace site is also deployed to Cloudflare Pages and reads the CMS marketplace catalog at build/runtime revalidation. The Studio admin SPA is a static Vite app deployed to Cloudflare Pages as well — see Studio API connectivity.
Studio API connectivity
The Studio SPA talks to the CMS over a single base URL resolved by
apps/studio/src/lib/api-base.ts (getApiBaseUrl()):
- Dev / Docker single-origin: leave
VITE_API_URLunset. The Studio uses same-origin requests — the Vite dev server proxies/apito the local CMS, and Docker serves the Studio from the same origin as the CMS. - Cloudflare Pages (e.g.
studio.lumibase.dev): the static SPA has no co-located backend, so it must call the CMS cross-origin. SetVITE_API_URLat build time to the CMS origin (e.g.https://api.lumibase.dev). The release workflow wires this from theLUMIBASE_CMS_PRODUCTION_URLrepository variable.
Because the Studio then calls the CMS from a different origin, the CMS must
allow that origin via CORS_ALLOWED_ORIGINS (see apps/cms/wrangler.toml).
Production rejects *, so list the exact Studio origin. If VITE_API_URL is
missing on a standalone deploy, the Studio falls back to same-origin and the
setup gate shows "Couldn't reach the server."
The dev / staging / demo environments instead serve Studio and the CMS from a single hostname (
<env>.lumibase.dev), soVITE_API_URLis empty (same-origin) and no CORS is needed. See Shared-domain environments.
Cloudflare Targets
| Target | Package | Output | Deploy command |
|---|---|---|---|
| CMS API Worker | @lumibase/cms | Worker bundle | pnpm --filter @lumibase/cms deploy |
| Documentation site | @lumibase/docs | apps/docs/dist | pnpm docs:deploy |
| Landing site | @lumibase/landing | apps/landing/out | pnpm landing:deploy |
| Marketplace site | @lumibase/marketplace | apps/marketplace/out | pnpm marketplace:deploy |
Run the build or dry-run command before deploying:
pnpm --filter @lumibase/docs build
NEXT_PUBLIC_USE_REAL_API=true NEXT_PUBLIC_CMS_API_URL=https://<cms-production-host> pnpm marketplace:build
pnpm --filter @lumibase/cms build
Marketplace smoke URLs after deploy: /, /extensions/, /categories/seo/, and /extensions/<slug>/.
Required Cloudflare Services
The CMS Worker can run with only environment variables for local development, but production expects the Cloudflare bindings described in apps/cms/wrangler.toml:
HYPERDRIVEfor pooled PostgreSQL access.CONFIG_CACHEfor KV-backed schema, permission and settings cache.MEDIAfor R2 media storage.SITE_ROOMDurable Object for per-site realtime WebSocket fan-out.- Cron Triggers for scheduled audit/login-attempt retention cleanup.
Secrets such as JWT_SECRET, Cloudflare Access values and database credentials must be set with Wrangler secrets or dashboard-managed secret variables, not committed to the repository.
Recommended Release Flow
- Install dependencies with
pnpm install. - Run
pnpm --filter @lumibase/docs buildfor the docs site. - Run
pnpm --filter @lumibase/cms buildto dry-run the Worker bundle. - Deploy docs with
pnpm docs:deploy. - Deploy the CMS Worker with
pnpm --filter @lumibase/cms deployafter production bindings and secrets are configured.
See Cloudflare deployment for the detailed Worker and Pages commands. See Private admin path for the production no-redirect policy that keeps the Studio entry point secret. See Multi-tenant deployment topologies for how to lay out cells, databases and domains when one deployment serves many tenants.