Deployment
A multi-app project doesn't deploy as one unit — each app in devora.config.ts maps to its own platform project (Vercel), site (Netlify), or process (self-hosted). This is inherent to how those platforms work, not a devora.js convention: a marketing site, dashboard, and admin panel are three independently deployable things.
Vercel
In the Vercel dashboard, add a new project per app, importing the same repo each time and setting Root Directory to apps/<name>. Each app already ships a committed vercel.json that points the build command at devora build --adapter=vercel for that app — nothing else needs configuring in the dashboard. If an app's auth mode is shared or isolated, set its session secret as an environment variable (DEVORA_SESSION_SECRET, or DEVORA_SESSION_SECRET_<APPNAME> for an isolated app) before deploying — an app with auth: "none" needs none of this. Changing an env var requires a redeploy to take effect.
Netlify
Same shape as Vercel: import the repo once per app, setting Base directory to apps/<name>. Each app ships a committed netlify.toml with the right build command and publish directory. One gotcha worth knowing up front: if Netlify auto-detected build settings on first import, its dashboard settings take precedence over netlify.toml and can silently break the build — clear the dashboard's Build command/Publish directory fields (or set them to match netlify.toml explicitly) if that happens. Environment variables follow the identical shared/isolated/none rule described above for Vercel.
For both platforms, devora deploy --adapter=vercel|netlify (see the CLI reference) is an optional convenience for pushing from the CLI once an app is linked with the platform's own vercel link/netlify link — it's not required if you're already deploying on every git push through the dashboard integration.
Docker
Each app builds and runs as its own container image, one app per image via a build arg:
docker build --build-arg APP_NAME=marketing -t devora-marketing . docker run -p 4173:4173 devora-marketing # shared/isolated apps need their session secret passed in docker run -p 4173:4173 -e DEVORA_SESSION_SECRET=... devora-dashboard # all apps together, via docker compose cp .env.example .env docker compose up --build
Under the hood this runs the same self-hosted Node adapter described below — Docker isn't a separate deployment target with its own adapter, just a way to package and run it.
Self-hosted VPS
For a bare server, build each app you want to run, start them, then generate a reverse proxy config from the domains already declared in devora.config.ts — no hand-written nginx/Caddy config needed:
devora build --app=marketing && devora build --app=dashboard && devora build --app=admin devora start # serves all built apps, sequential ports devora generate:proxy --target=nginx # or --target=caddy # install the generated config for your distro, then reload nginx/caddy
The generated nginx config listens on plain HTTP only — issuing a real TLS certificate needs a real, DNS-resolving domain, so the documented next step there is certbot --nginx -d <domain>. Caddy needs no such step: automatic HTTPS via ACME is its default behavior for any domain it can prove ownership of. To keep devora start running across reboots/crashes, a systemd unit template is available as a starting point to adapt to your own host, rather than a drop-in guarantee.