Guide

Deployment

The dashboard is the single deployable artifact: one Nuxt app serving the UI, the control plane, and authentication from one origin.

The dashboard is the single deployable artifact: one Nuxt app serving the UI, the control plane, and authentication from one origin.

Build and run

aube run build
node apps/dashboard/.output/server/index.mjs

nuxt build emits a self-contained .output/ bundle — no node_modules needed at runtime. The server listens on port 3000 by default; override with PORT.

Production checklist

  • Session secret — set NUXT_BETTER_AUTH_SECRET (this exact name; the development fallback is ignored in production). Generate with openssl rand -base64 32.
  • Postgres — point DATABASE_URL at a managed database and apply the schema once with aube run db:migrate. See Database.
  • Auth policy — decide AUTH_ENABLE_SIGNUP, GitHub OAuth credentials, and organization flags, then build with them set: the auth pages capture capabilities at build time. See Authentication.
  • Mail — configure Resend (RESEND_API_KEY; MAIL_PROVIDER=resend is optional) or set MAIL_PROVIDER=smtp with its SMTP variables. With neither, console only logs. Required if invitations or organizations are enabled. See Mails.
  • Control plane — issue bearer tokens via AGENT_ZERO_CONTROL_PLANE_TOKENS, allow-list repositories via AGENT_ZERO_CONTROL_PLANE_REPOSITORIES, and grant modes via AGENT_ZERO_CONTROL_PLANE_MODES. Without them, mutations are rejected. See Protect endpoints.
  • Webhooks — set GITHUB_WEBHOOK_SECRET and AGENT_ZERO_CHECKOUT_PATH; the webhook route fails closed (503) until both are set. Configure the webhook on the source-control side per Source-control providers.
  • Isolated execution — production runs that write require runner.isolation: container in repository policy, with an image and resource limits. The included LocalRunner is for trusted local development only. See the Safety model.
  • Model provider — select the provider in repository policy and set its credential environment variable. See Model providers.

Task history storage

Task history uses the ViteHub KV Runtime Helper: filesystem-backed fs-lite by default (.data/kv), with Cloudflare KV, Deno KV, or Upstash available as driver configuration without touching application code. Records are redacted before they are written.

Hosted sandboxes

For hosted execution, the provider-neutral RunnerPool supports vendor adapters (ViteHub, Cloudflare Sandbox, Vercel Sandbox were evaluated — see Sandbox providers). Quota checks run before provisioning, leases are bounded, and expired sandboxes are stopped.

Rebuild triggers

Rebuild the app whenever you change:

  • AUTH_ENABLE_SIGNUP, GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET, or organization flags (login-page capabilities are captured at build time);
  • anything in packages/* (the server bundle inlines them).

Vercel

apps/dashboard ships its own vercel.json so it can be deployed as a Vercel project with Root Directory set to apps/dashboard: the install and build commands cd back to the workspace root so aube and Turborepo resolve the monorepo correctly.

The build command sets NITRO_PRESET=vercel. nuxt.config.ts registers vite-hub/nuxt with a deployment preset, and that preset pins Nitro's own, so the build target is a deliberate choice rather than something Nitro auto-detects: without that variable every build emits the self-hosted node-server bundle in .output/, which Vercel cannot serve — it fails with No Output Directory named "dist" found. With it, config/env.ts resolves the vercel preset and the build writes .vercel/output (Vercel's Build Output API) instead. VITEHUB_HOSTING selects the same target and takes precedence.

Because they select the target, NITRO_PRESET and VITEHUB_HOSTING are declared on the app build tasks in turbo.jsonc: Turborepo's strict environment mode hides a variable a task does not declare (NITRO_* is forwarded by its Nuxt framework inference, VITEHUB_HOSTING is not), and declaring them keeps the target in the cache key so a self-hosted build is never restored into a hosted one. Both .output/** and .vercel/output/** are listed as build outputs for the same reason.

On a hosted preset the KV Runtime Helper resolves the host's own driver rather than the filesystem one, because a serverless function has nowhere durable to write: on Vercel that is Upstash, so set KV_REST_API_URL and KV_REST_API_TOKEN or task history fails at runtime. See Database.

Upstream version mismatchvite-hub@0.0.3's vercel plan checks for a server function at .vercel/output/functions/__server.func/index.mjs, while the installed nitropack@2.13.4 emits — and routes to — __fallback.func. The bundle is correct; only the name ViteHub looks for is not, so nuxt.config.ts links that name to the emitted function for the length of the check and removes the link afterwards. That bridge is registered as a Nitro module, not under nitro.hooks: a handler placed there replaces the preset's own handler for the same hook, and the vercel preset writes config.json and every .vc-config.json from its compiled hook — without them the directory exists but Vercel cannot read it, and the build fails with the same missing-dist error. Delete the module and viteHubVercelEntryName in config/env.ts once a ViteHub release expects the preset's own layout.

apps/marketing sets NITRO_PRESET the same way. It composes no ViteHub integration, so the variable only picks its Nitro preset, and it has no KV store to configure.

Documentation site

apps/docs is not deployed with the dashboard. It ships its own vercel.json so it can be deployed as a separate Vercel project with Root Directory set to apps/docs: the install and build commands cd back to the workspace root so pnpm and Turborepo resolve the monorepo correctly, and the build output is .output.

Copyright © 2026