Skip to content

Deploy Nuxt

A Nuxt app deploys in one of two ways. Generated with nuxi generate, it is a static site and needs no changes. Rendered on a server, it needs the deploybase Nitro preset, which runs the server parts on a deploybase function.

Setting Static (nuxi generate) Server (with @deploybase/nitro-preset)
Build command npm run generate npm run build
Output directory .output/public .deploybase/v1/static
Image node:24-alpine node:24-alpine

Detection is automatic when your repository has a nuxt.config.* file, and it picks the column from your package.json: installing @deploybase/nitro-preset switches to the server build. Every value above is editable per project.

If your build script runs nuxt build and there is no generate script and no preset, detection stops with a fix: a server build has nothing to publish on its own. Either install the preset as below, or generate a static site.

A preset written for another host, such as cloudflare-pages, vercel or netlify, produces output deploybase cannot run. Remove it from nitro.preset in nuxt.config.ts, and remove NITRO_PRESET from the build environment if you set it there.

  • If every page can be built ahead of time, generate the site and keep the static defaults.
  • If some pages must render per request, use @deploybase/nitro-preset, as the next section shows.

@deploybase/nitro-preset runs your Nuxt server on a deploybase function in Paris (Node 22): pages rendered on demand, server/api and server/routes handlers. Prerendered pages and assets are served from the CDN and never start the server.

Two conditions apply before you start:

  • Your team needs HTTP functions, which come with the Starter, Pro and Scale plans. On Free, the build still succeeds and the prerendered pages go live, but every on-demand page answers 404, and the build log says why:

    ⚠️ This build includes server-rendered routes, which need a paid plan. Only the static pages were deployed; server routes will answer 404

    After upgrading, deploy again: the server is set up only when a deployment is built.

  • On-demand pages render on every address of the site: the project’s deploybase address, branch previews and custom domains.

Terminal window
npm install @deploybase/nitro-preset
nuxt.config.ts
export default defineNuxtConfig({
nitro: {
preset: '@deploybase/nitro-preset',
},
});

Keep the build defaults from the server column above. In a monorepo, set the project’s Root directory to the folder holding nuxt.config.ts, so the output directory .deploybase/v1/static is found next to it.

Serve the site from the root of its domain: a baseURL other than / (app.baseURL, or NUXT_APP_BASE_URL in the build environment) fails the build with a message saying so.

Every page renders on demand unless a route rule prerenders it. Prerender everything that does not change per request, so it is served from the CDN without starting the server:

nuxt.config.ts
export default defineNuxtConfig({
nitro: { preset: '@deploybase/nitro-preset' },
routeRules: {
'/': { prerender: true },
'/about': { prerender: true },
'/blog/**': { swr: 600 },
},
});

Variables with Runtime ticked on the project’s Environment page reach your server through process.env, so Nuxt’s runtime config picks up the NUXT_ ones:

nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
cmsToken: '', // set at runtime by NUXT_CMS_TOKEN
},
});
server/api/posts.get.ts
export default defineEventHandler((event) => {
const { cmsToken } = useRuntimeConfig(event);
// ...
});

A production deployment gets the production values and a branch preview the preview values, each captured when the deployment is built. To change what a running server sees, redeploy after saving the variable. Rolling back to an older deployment brings back the values that deployment was built with.

nuxt build writes everything deploybase needs into .deploybase/v1/, next to nuxt.config.ts:

Path What it is
config.json Tells deploybase the server answers every path no static file matches
static/ Client assets, prerendered pages and public/. Published to the CDN
server/ The Nitro server, with entry.mjs as its entry. Never public
  1. A request for a file that exists in static/ is served from the CDN. A static file always wins.
  2. Any other request goes to your server, whatever the method. That includes a missing file under /_nuxt/, which gets your app’s 404 response.
Nitro feature On deploybase
useStorage() and the default data mount In memory: per instance, gone when the server scales to zero. Configure a remote unstorage driver for anything that must persist
swr and cache route rules, defineCachedEventHandler Work, cached in that memory, so each instance keeps its own copy. Responses are not cached at the edge
headers route rules Sent by the server on on-demand responses. Not applied to prerendered pages or assets yet
redirect, proxy and cors route rules Handled by the server, so they start it like any on-demand page
Scheduled tasks (scheduledTasks) Do not run: nothing keeps the server awake. The build log warns
WebSockets (experimental.websocket) Not supported. Server-sent events and streamed responses work. The build log warns
experimental.database with the default SQLite No shared disk: each instance gets its own empty database. The build log warns

The limits that apply to every server-rendered site apply here too:

  • Promoting a preview. A preview deployment’s server was built with the preview variables, so promoting it to production is refused with 409. Deploy the commit on the production branch instead. Rolling back to an older production deployment works.
  • Cold starts. The server scales to zero when it goes quiet, sooner on a branch preview than in production, and the first request after that waits several seconds. The functions reference has the idle windows.
  • 50 second deadline. A response must start within 50 seconds, and a streamed response must also finish within that time.
  • Request body size. A body over the HTTPS request limit is refused with 413.
  • No edge caching of server responses. Every on-demand response is sent with Cache-Control: private, no-store, whatever your code sets. Prerender what can be cached.

Every on-demand page answers 404, but the prerendered ones work. The build log has no SSR output detected line, so deploybase did not find .deploybase/v1/config.json. Check that nitro.preset is @deploybase/nitro-preset, and in a monorepo that the project’s root directory is the folder holding nuxt.config.ts. On Free, the build log says the server needs a paid plan instead.

The build fails on baseURL. Remove app.baseURL from nuxt.config.ts and NUXT_APP_BASE_URL from the build environment. A deploybase site is served from the root of its domain.

A value saved in the project’s environment does not show up. Variables are captured when the deployment is built. Redeploy, and check that Runtime is ticked and the name starts with NUXT_ if you read it through useRuntimeConfig.

Live f79d25b6 built