Skip to main content

Deploying

One Worker serves the built SPA and every /api route, including the voice WebSocket. It ships in two flavours, chosen by Wrangler environment.

FlavourCommandWorker nameStore
D1 (default)npm run deployai-pob-claimpilotchatthe DB binding to D1 claimpilot-chat
Neonnpm run deploy:neonai-pob-claimpilotchat-neonNeon over DATABASE_URL

The Cloudflare account is pinned in api/wrangler.jsonc, so local commands and Workers Builds always target the same one. Named Wrangler environments inherit nothing, so the neon environment restates its assets, vars and gateway ids.

First deploy of an environment​

  1. Set the secrets. Secrets are per environment: a secret put on the default environment is not visible to --env neon.

    cd api
    npx wrangler secret put GEMINI_API_KEY
    npx wrangler secret put CF_AIG_TOKEN # if the AI Gateway is authenticated
    npx wrangler secret put EMBED_KEY # optional budget guard
    npx wrangler secret put DATABASE_URL --env neon # Neon flavour only
  2. Create the schema.

    npm run db:migrate:remote # D1
    npm run db:migrate:neon # Neon
  3. Check the pinned settings in api/wrangler.jsonc: models, voice, DATABASE_PROVIDER, the AI Gateway ids and ALLOWED_ORIGINS. A wrangler deploy sets only what is in this file, so nothing set by hand in the dashboard survives.

  4. Deploy.

    npm run deploy # or npm run deploy:neon

    This builds the SPA and the embed bundle, then runs wrangler deploy.

  5. Load claims with the generator (--target d1-remote or --target neon) or copy-claims, for example:

    npm run copy-claims -- --from d1-local --to d1-remote
  6. Check it. See After a deploy.

The gateway token

The AI Gateway ids are pinned in wrangler.jsonc, so a deploy turns the gateway on. If the gateway is authenticated and CF_AIG_TOKEN is not set for that environment, every model call fails with AiGatewayError 2009 Unauthorized. Set the secret before deploying.

Routine deploys​

npm run test:all && npm run deploy

New migrations are applied before the deploy that needs them (db:migrate:remote or db:migrate:neon). Migrations are additive by convention, so the running version keeps working while they apply.

Each build stamps version.json. Open tabs poll it every minute and show A new version is available with a refresh button once the new deployment lands.

Auto-deploy from GitHub (Workers Builds)​

Connect the repository in the Cloudflare dashboard with:

SettingValue
Root directory/
Build commandnpm run build
Deploy commandnpm run deploy -w api (or npm run deploy:neon -w api)
Worker namemust match name in wrangler.jsonc

Secrets and the remote schema and data are set up once, outside the build, as above.

After a deploy​

CheckHow
The Worker is up and configuredGET /api/health reports database, the model, configured: true, and the gateway id
Claims loadOpen the site; the root URL opens a random claim
Chat works end to endAsk a question; an activity chip appears, then an answer with lookups
Voice worksThirty seconds on the microphone. Voice depends on the Worker opening an outbound WebSocket to Gemini Live, the one thing that behaves differently from local development
Embedding works for each hostTheir page loads the element and answers; their origin is in ALLOWED_ORIGINS

Custom domains​

Add a routes entry to wrangler.jsonc for the environment. Add the new origin to ALLOWED_ORIGINS only if pages on other origins will embed the assistant from it; same-origin pages need nothing.

Rolling back​

Use Deployments in the Cloudflare dashboard, or npx wrangler rollback from api/. A rollback does not undo a migration, which is another reason to keep migrations additive.