Deploy
Provision D1 and R2, apply migrations, set secrets and deploy the engine and web Workers, plus the docs site.
OrderLoop deploys as two Workers in one Cloudflare account:
| Worker | Config | Role |
|---|---|---|
orderloop-engine |
apps/engine/wrangler.jsonc |
OrderAgent Durable Object, orderloop-order and orderloop-replenish Workflows, Workers AI. No public URL (workers_dev and preview URLs are off); reached only through the web app’s service binding |
orderloop-web |
apps/web/wrangler.jsonc |
Dashboard, editor, REST API. Binds the engine as ENGINE (entrypoint EngineApi) |
Both bind the same D1 database (orderloop) and R2 bucket (orderloop-docs).
First deploy
Section titled “First deploy”pnpm exec wrangler login./scripts/provision.sh # creates D1 `orderloop` and R2 `orderloop-docs`; safe to re-runpnpm --filter @orderloop/web db:migrate:remotepnpm --filter @orderloop/web exec wrangler secret put APP_PASSWORDpnpm --filter @orderloop/web exec wrangler secret put WEBHOOK_SECRETpnpm run deploy # engine first (web binds to it), then webIf provision.sh prints a database_id, put it in the d1_databases entry of both
wrangler.jsonc files. Change the web app’s routes to your own hostname.
Use pnpm run deploy, not pnpm deploy: the bare form is pnpm’s built-in deploy command and does
something else entirely.
Order matters
Section titled “Order matters”- Migrations before code. Apply remote D1 migrations before deploying code that reads a new table or column.
- Engine before web. The web Worker’s service binding needs the engine to exist.
Workflow names (orderloop-order, orderloop-replenish) must be unique in the account.
Email intake
Section titled “Email intake”To start orders from email, enable Email Routing on the zone and route the intake addresses to
orderloop-engine after the engine is deployed. Enabling it replaces the zone’s MX records. The
steps are in Email intake.
Settings for production
Section titled “Settings for production”- Set
TIME_SCALEto"1"inapps/engine/wrangler.jsonc, or waits and timeouts stay compressed (the default"1440"turns a day into a minute). - Set
AI_GATEWAY_IDto route model calls through AI Gateway for caching, rate limits and logs. - After the first deploy, sign in with no email and
APP_PASSWORD, open Team and add people with their roles, and create API tokens for other systems.APP_PASSWORDstays as a break-glass operator sign-in. See Team and roles.
All settings are listed in Configuration.
Production deploys from CI: merging to main is the release. .github/workflows/ci.yml runs lint,
type-check, build and tests on every push and pull request. On main it then migrates D1, deploys
the engine, deploys the web app, smoke-tests /health and deploys these docs, in that order, so a
change never reaches production before its migration. The deploy job needs the repository secrets
CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID; without them it does nothing.
Each deploy step runs through a small retry helper (three attempts, 15 then 30 seconds apart),
because the Cloudflare API occasionally fails a request outright (codes 7403, 10013) and every
step is safe to repeat. If the job still fails, re-run its failed jobs in GitHub Actions rather
than deploying from a laptop. The manual commands under First deploy are for
setting up a new account.
The docs site
Section titled “The docs site”These docs are apps/docs (@orderloop/docs), a static Starlight site served by a static-assets
Worker, orderloop-docs, with no runtime code.
pnpm docs:dev # local previewpnpm docs:build # static build into apps/docs/distpnpm docs:deploy # build, then wrangler deployThe reference pages (node catalog, built-in flows, event and status lists) and the OpenAPI explorer render from the source at build time, so rebuild and redeploy the docs whenever those change.