What runs where
Library mode on Vercel
createOrchestrator() returns a Web-standard handler, and mounting it as a
Next.js route works on Vercel: requests are answered, the
access gate applies, and a page rendered by the same
function reads its drafts in-process. What does not hold is the state behind it.
- A deployed function’s filesystem is read-only outside
/tmp, and/tmpbelongs to one instance and disappears with it. - Vercel runs as many instances as traffic needs. Each one would keep its own drafts.
GET /status/planner
reports persistence.ok: false with the reason when the store could not open.
See state and backups.
When you do mount library mode on Vercel, for example for a preview environment
whose drafts may be thrown away:
- Pass
waitUntilfrom@vercel/functions, or Next’safter(), tocreateOrchestrator({ waitUntil }). Background check runs after a publish or an edit are handed to it, so they are not cut off when the response is sent. - Chat replies stream over server-sent events, so the function’s maximum duration bounds the longest chat turn.
- Set
ACCESS_PASSWORD_HASHorORCHESTRATOR_ACCESS_TOKEN. UnderNODE_ENV=production, library mode with neither refuses every request.
Site on Vercel, orchestrator elsewhere
The site reads drafts from the orchestrator over HTTP and publishes through its own/api/editor/publish.
Write every origin without a trailing slash.
Publishing from a site on Vercel
Two things about publishing change the moment the site is on Vercel rather than on your machine.- The publish route is closed until you configure it.
POST /api/editor/publishrefuses every request with 401 underNODE_ENV=productionwhen nopublishSecretis set, and namesPUBLISH_TOKENin the refusal. Set the same value on the site project and on the orchestrator. - A deployed site cannot rewrite its own content file. The runtime
filesystem is read-only outside
/tmp, so a publish handler that writes a JSON file under the project —createJsonFilePublishHandler, orjsonFileAdapter({ writeOnPublish: true })— works innext devand fails after deploy. Publishing in production goes to something that persists: a CMS, a database, or a git commit that triggers a rebuild.
The editor on Vercel
The editor is a static Vite app inapps/editor, and its vercel.json already
rewrites every path to index.html.
- Root directory:
apps/editor - Build command:
pnpm --filter @ai-site-editor/editor build - Output directory:
dist
The alternative to a build is the prebuilt editor in
@avocadostudio-ai/cli.
Run avocado-studio start --host 0.0.0.0 on any Node 22 host. On a
non-loopback bind it leaves the secrets out of the page for the same reason. See
CLI and packages.
This repository’s demo site
The steps above are for your own site. Deployingapps/site from this
repository has two details of its own:
- Root directory
apps/site. Its build runsscripts/sync-published-content.mjsand thennext build. - With
ORCHESTRATOR_URLunset, the build keeps the committedlib/published-content.jsonand the site needs no orchestrator at runtime. With it set,SITE_PUBLISH_SITE_IDis required or the build fails, andSITE_PUBLISH_SESSIONdefaults todev.
NEXT_PUBLIC_ENABLE_EDITOR=1 only exposes the /catalogue route. It has no
effect on draft mode or on the preview bridge.
To keep editing away from production, give the editor a separate staging site
to frame, and point the git publish target at a staging branch with
PUBLISH_GIT_BRANCH.
Orchestrator from source
The standalone orchestrator can also run from source on any Node host with a persistent disk, without the Docker image. It runs TypeScript directly withtsx, which is a production dependency, and its build step is a typecheck.
- Node 22 or later
- Root directory:
apps/orchestrator - Build:
pnpm install --frozen-lockfile && pnpm --filter @ai-site-editor/orchestrator build - Start:
pnpm --filter @ai-site-editor/orchestrator start, which runstsx src/index.ts - Mount the persistent disk where
ORCHESTRATOR_DB_FILEpoints - One instance only
Production troubleshooting
The preview shows the published page, never the draft. Check these in order:- The site’s
DRAFT_MODE_SECRETdiffers from the one the editor uses. The preview degrades to published content rather than failing. - The editor could not fetch its credentials. A public editor needs
ACCESS_PASSWORD_HASH,DRAFT_MODE_SECRETandPUBLISH_TOKENon the orchestrator, orGET /editor/credentialsanswers 403. - The site reads drafts from a different orchestrator, or with no access token where one is required. A 401 on the draft read is logged on the site.
NEXT_PUBLIC_EDITOR_ORIGIN or AVOCADO_EDITOR_ORIGINS. The bridge only talks
to an origin on that list.
The editor says it cannot reach the orchestrator, but curl gets a 200.
That is CORS. ORCHESTRATOR_CORS_ORIGINS on a standalone orchestrator, or
corsOrigins in library mode, must include the editor’s origin.
The editor has no pages to edit. The editor seeds the orchestrator from the
site’s /api/editor/pages. Without that route, the orchestrator has no draft
pages for the site.
Edits vanish between requests or after a deploy. The orchestrator’s state is
not on a persistent disk, or more than one instance is running. See
library mode on Vercel.