One repo, several Vercel projects: deploying a multi-app project

Each app in a Devora.js project is its own Vercel project. The settings, the session store, the api/ folder trap, and the repo-root alternative.

A Devora.js project with three apps is three Vercel projects that import the same repository. That's not a Devora.js convention; it's how Vercel projects work — one build and one set of domains each. The framework's own example apps run this way (live demos, deployed by the maintainer).

The settings, per app

  1. Add New → Project, import the repo, and set Root Directory to apps/<name>.
  2. Leave the build settings alone. Every app has a committed vercel.json:
    {
      "$schema": "https://openapi.vercel.sh/vercel.json",
      "buildCommand": "cd ../.. && ./node_modules/.bin/devora build --app=app --adapter=vercel",
      "framework": null
    }
    "framework": null stops Vercel from running a plain vite build, and the command goes to the repo root, where devora.config.ts and the shared packages are. Keep "Include files outside the Root Directory" on.
  3. Environment variables: DEVORA_SESSION_SECRET for apps with auth: "shared" (the same value in every shared app), DEVORA_SESSION_SECRET_<APP> for an isolated one, nothing for auth: "none". Redeploy after changing them.

Two things that break on serverless

The session store. A Vercel function runs as many short-lived instances. sessions: { store: "memory" } gives each its own empty store, so logins don't stick. Point shared.sessions.store at a module backed by your database or Redis. The build tells you:

$ ./node_modules/.bin/devora build --app=app --adapter=vercel
[devora] "app" Vercel runtime: nodejs24.x (from the running Node 24 (satisfies engines.node ">=20"))
[devora] "app" preflight warning: shared.sessions.store is "memory" — on serverless each function
instance has its own empty store, so logins won't stick. Use a DB-backed store before relying on
sessions in production.

A top-level api/ folder. In a Vercel project, api/ is Vercel's own functions folder: every file in apps/<name>/api/ becomes a separate function next to the one Devora builds (and counts against the Hobby plan's limit). Apps created since 0.3.2 use endpoints/ (apiDir in app.config.ts); URLs stay under /api. The preflight check warns when it finds an api/ folder.

The alternative: Root Directory = the repo root

If you can't move an api/ folder yet, leave Root Directory empty and write the build output where Vercel looks for it, per project:

./node_modules/.bin/devora build --app=app --adapter=vercel --out=.vercel/output

Set that as the build command in each project's dashboard (one repo-root vercel.json can't hold several commands), with Framework Preset "Other".

One login across the apps

On separate subdomains, browsers keep a separate cookie per host. To share one login between app.example.com and admin.example.com, set shared.sessions.cookie.domain: "example.com"; the build checks every shared app is under it. Bearer tokens aren't affected.

The full guide, including Netlify, Docker and a plain VPS, is on Deployment.