Deploy

Deploying with Void

Ship the app with void deploy, set secrets, and bootstrap the first admin in production.


The reference app is a Void app on Cloudflare Workers with D1 and R2. void.config.ts pins the Worker, the D1 database (binding DB, migrations in db/migrations), and the R2 bucket (binding BUCKET).

bunx void db migrate --remote   # apply app migrations
void deploy                     # build and deploy

The CMS tables need no migration: the engine creates and upgrades them on its first request. Content, collection definitions, and pages are data, so changing them never needs a deploy either.

Secrets

void secret put OPEN_CMS_INIT_KEY    # first-admin bootstrap
void secret put CMS_WEBHOOK_URL      # optional outbox target
void secret put CMS_WEBHOOK_SECRET   # optional signature secret

First admin

With the user table empty, sign up once at /api/auth/sign-up/email with the x-init-key header (see Quick start). Later attempts return 403 SIGNUP_DISABLED; a missing key on the server returns SETUP_NOT_CONFIGURED, a wrong one INVALID_INIT_KEY. Invite everyone else from /admin/users; the last admin cannot be demoted (LAST_ADMIN).

Keeping these docs in sync

The database is the source of truth. The reference app's bun run docs:sync --url https://<host> --key cms_... pushes the bundled docs through the REST API: it matches by slug, updates changed docs, creates missing ones, and publishes them with an admin key (or requests review with an editor key).