Development workflow
One origin
Astro renders the pages, Nitro serves /api, and both come off one origin —
no CORS, no API base URL to configure, one thing to deploy.
npm run dev # Astro on :4321, Nitro on :3000, /api proxied
npm run build # astro build, then vite build
npm run preview # the real thing: one server, both halves
| development | production | |
|---|---|---|
| Pages | astro dev on :4321 |
static files in dist/, served by Nitro |
| API | vite dev (Nitro) on :3000 |
Nitro server in .output/ |
| One origin via | Astro’s dev proxy (vite.server.proxy in astro.config.mjs) |
Nitro’s publicAssets, which mounts dist/ at / |
Build order matters
npm run build runs Astro first, then Nitro — that order matters, because the
Nitro build folds Astro’s finished dist/ into .output/public/.
The dev script
scripts/dev.mjs runs both dev servers. It is dependency-free and worth
reading: astro dev stays in the foreground on a TTY but detaches into a
background daemon when its output is piped, and the script reports that rather
than assuming it crashed.
Type checking
Two tsconfigs, because the halves target different runtimes: tsconfig.json
(Astro, DOM) and tsconfig.server.json (Nitro, Node). npm run typecheck runs
both.
Changing the API port
ZN_API_PORT (default 3000) sets the Nitro port and the proxy target
together — astro.config.mjs, vite.config.ts and scripts/dev.mjs all read
it from .env, so change it in one place. A value already in the environment
wins over the file, so ZN_API_PORT=3005 npm run dev is still a one-off.
