部署

得益于 Nitro,同一份代码可以部署到裸机 Node 服务器、Serverless、Edge 运行时或纯静态托管 —— 通常只要换个 preset 就行。

构建产物

pnpm build 会生成两个目录:

.output/
├── server/            # 入口 + 面向 Serverless 的服务端代码
└── public/            # 静态资源与预渲染 HTML

pnpm preview 起一个本地等价于生产的服务器。

纯静态托管用 pnpm generate,它会预渲染所有可达路由,只输出 .output/public/

Node.js 服务器(默认 preset)

适合 VPS / Docker / 传统 PaaS:

node .output/server/index.mjs
# 监听 http://0.0.0.0:3000

支持的环境变量:

  • NITRO_PORT / PORT(默认 3000
  • NITRO_HOST / HOST(默认 0.0.0.0
  • NITRO_SSL_CERT / NITRO_SSL_KEY —— 开发用 HTTPS

进程管理(PM2)

// ecosystem.config.cjs
module.exports = {
  apps: [{
    name: 'my-nuxt-app',
    port: '3000',
    exec_mode: 'cluster',
    instances: 'max',
    script: './.output/server/index.mjs',
  }],
}

pm2 start ecosystem.config.cjs 就开启多核集群模式。

Docker

一份最小多阶段镜像:

FROM node:22-alpine AS build
WORKDIR /app
COPY . .
RUN corepack enable && pnpm install --frozen-lockfile && pnpm build

FROM node:22-alpine
WORKDIR /app
COPY --from=build /app/.output ./.output
EXPOSE 3000
CMD ["node", ".output/server/index.mjs"]

静态托管

两种玩法:

  1. SSG 保留 SSR 内容ssr: true,默认)。nuxt generate 预渲染路由,生成 200.html / 404.html 作为动态路由的 SPA fallback。
  2. 纯 CSR SPAssr: false)。nuxt generate 会输出一个标准 index.html,在浏览器里 hydrate。

.output/public/ 上传到任意静态托管 —— S3、Cloudflare Pages、Netlify、Vercel、GitHub Pages 都行。

Serverless / Edge 预设

Nuxt 自带 15+ Nitro preset。配置里指定:

export default defineNuxtConfig({
  nitro: { preset: 'vercel' },
})

或者通过环境变量:

NITRO_PRESET=vercel pnpm build
NITRO_PRESET=netlify pnpm build
NITRO_PRESET=cloudflare-pages pnpm build
NITRO_PRESET=deno-deploy pnpm build
NITRO_PRESET=aws-lambda pnpm build

大多数托管平台(Vercel、Netlify、Cloudflare Pages)能自动识别 Nuxt 并选中 preset。

环境变量

仅服务端的密钥放 runtimeConfig,用 NUXT_* 环境变量覆盖:

NUXT_API_SECRET=prod_secret
NUXT_PUBLIC_API_BASE=https://api.example.com

客户端需要的 key 放到 runtimeConfig.public

发版 checklist

  • [ ] pnpm typecheck / pnpm lint / pnpm test 全部通过。
  • [ ] 本地 pnpm build 成功。
  • [ ] 平台上配好必要环境变量(NUXT_*、DB URL、密钥)。
  • [ ] routeRules 检查一遍 —— 能预渲染的预渲染,必须 SSR 的才 SSR。
  • [ ] 公共路由配好 cache / swr 头。
  • [ ] 需要健康检查的平台加上 /healthz
  • [ ] 日志收集已接入(大多数平台 console 就够)。
  • [ ] 错误上报插件已启用(vue:error + 服务端 error 钩子)。

CDN / Cloudflare 注意事项

用 Cloudflare 代理时,关掉这两项:

  1. Speed → Content Optimization → Rocket Loader™
  2. Security → Email Address Obfuscation

它们注入的脚本会破坏 hydration。

回滚方案

  • Serverless 平台至少保留两个构建版本 —— 旧页面 tab 还持有老的 chunk URL,要让它们能拿到响应(或让 Nuxt 的 chunk-error 处理器硬刷新)。
  • 打 Git tag(git tag v1.2.3),便于快速回滚。

不止 Node

  • Deno —— NITRO_PRESET=deno-deploydeno-server
  • Bun —— 目前用 Node preset 也能跑;原生 Bun preset 处于 beta。
  • Workers / Workerd —— cloudflare-pagescloudflare-workers preset 一等公民支持 routeRules 映射。

有了 preset 系统,换运行时就是一次配置更改 + NITRO_PRESET。“一次构建、随处部署”,这就是 Nuxt 给你的承诺。

部署

藉由 Nitro,同一份程式碼可部署至裸機 Node 伺服器、Serverless、Edge 執行時或純靜態代管 —— 通常只需更換 preset。

建置產物

pnpm build 會產生兩個目錄:

.output/
├── server/            # 入口 + 面向 Serverless 的伺服器程式碼
└── public/            # 靜態資源與預渲染 HTML

pnpm preview 會啟動與正式環境等效的本地伺服器。

純靜態代管用 pnpm generate,它會預渲染所有可達路由,僅輸出 .output/public/

Node.js 伺服器(預設 preset)

適合 VPS/Docker/傳統 PaaS:

node .output/server/index.mjs
# 監聽 http://0.0.0.0:3000

支援的環境變數:

  • NITRO_PORT / PORT(預設 3000
  • NITRO_HOST / HOST(預設 0.0.0.0
  • NITRO_SSL_CERT / NITRO_SSL_KEY —— 開發用 HTTPS

進程管理(PM2)

// ecosystem.config.cjs
module.exports = {
  apps: [{
    name: 'my-nuxt-app',
    port: '3000',
    exec_mode: 'cluster',
    instances: 'max',
    script: './.output/server/index.mjs',
  }],
}

pm2 start ecosystem.config.cjs 即進入多核叢集模式。

Docker

最小多階段映像:

FROM node:22-alpine AS build
WORKDIR /app
COPY . .
RUN corepack enable && pnpm install --frozen-lockfile && pnpm build

FROM node:22-alpine
WORKDIR /app
COPY --from=build /app/.output ./.output
EXPOSE 3000
CMD ["node", ".output/server/index.mjs"]

靜態代管

兩種玩法:

  1. SSG 保留 SSR 內容ssr: true,預設)。nuxt generate 預渲染路由,產生 200.html404.html 作為動態路由的 SPA fallback。
  2. 純 CSR SPAssr: false)。nuxt generate 會輸出標準 index.html,於瀏覽器 hydrate。

.output/public/ 上傳至任一靜態代管 —— S3、Cloudflare Pages、Netlify、Vercel、GitHub Pages 皆可。

Serverless/Edge 預設

Nuxt 內建 15+ Nitro preset。於設定指定:

export default defineNuxtConfig({
  nitro: { preset: 'vercel' },
})

或透過環境變數:

NITRO_PRESET=vercel pnpm build
NITRO_PRESET=netlify pnpm build
NITRO_PRESET=cloudflare-pages pnpm build
NITRO_PRESET=deno-deploy pnpm build
NITRO_PRESET=aws-lambda pnpm build

多數代管平台(Vercel、Netlify、Cloudflare Pages)會自動識別 Nuxt 並選中 preset。

環境變數

僅伺服器端的金鑰置於 runtimeConfig,以 NUXT_* 環境變數覆寫:

NUXT_API_SECRET=prod_secret
NUXT_PUBLIC_API_BASE=https://api.example.com

客戶端需要的 key 置於 runtimeConfig.public

發版 checklist

  • [ ] pnpm typecheckpnpm lintpnpm test 全數通過。
  • [ ] 本地 pnpm build 成功。
  • [ ] 平台已設定必要環境變數(NUXT_*、DB URL、金鑰)。
  • [ ] routeRules 再次檢查 —— 能預渲染的預渲染,必須 SSR 的才 SSR。
  • [ ] 公共路由設定合適的 cacheswr 標頭。
  • [ ] 需要健康檢查的平台加上 /healthz
  • [ ] 日誌收集已接入(多數平台 console 即可)。
  • [ ] 錯誤回報外掛已啟用(vue:error + 伺服器 error 鉤子)。

CDN/Cloudflare 注意事項

採用 Cloudflare 代理時,請關閉:

  1. Speed → Content Optimization → Rocket Loader™
  2. Security → Email Address Obfuscation

它們注入的指令碼會破壞 hydration。

回滾方案

  • Serverless 平台至少保留兩個建置版本 —— 舊頁面 tab 仍持有舊 chunk URL,需令其能取得回應(或讓 Nuxt 的 chunk-error 處理器強制重新整理)。
  • 打 Git tag(git tag v1.2.3),便於快速回滾。

不止 Node

  • Deno —— NITRO_PRESET=deno-deploydeno-server
  • Bun —— 目前用 Node preset 亦可;原生 Bun preset 處於 beta。
  • Workers/Workerd —— cloudflare-pagescloudflare-workers preset 為一等公民,支援 routeRules 映射。

有了 preset 系統,切換執行時僅為一次設定變更 + NITRO_PRESET。「一次建置、隨處部署」,正是 Nuxt 的承諾。

Deployment

Thanks to Nitro, a Nuxt app can ship to a bare-metal Node server, a serverless function, a CDN edge runtime, or pure static hosting — with the same codebase and usually no more than a preset change.

Build outputs

pnpm build writes two trees:

.output/
├── server/            # entrypoint + serverless-friendly server code
└── public/            # static assets & prerendered HTML

pnpm preview spins up a production-equivalent local server.

For fully static hosting, pnpm generate prerenders every reachable route and emits only .output/public/.

Node.js server (default preset)

Best for VPS / Docker / traditional PaaS:

node .output/server/index.mjs
# listens on http://0.0.0.0:3000

Respected env vars:

  • NITRO_PORT / PORT (default 3000)
  • NITRO_HOST / HOST (default 0.0.0.0)
  • NITRO_SSL_CERT / NITRO_SSL_KEY — dev-only HTTPS

Process manager (PM2)

// ecosystem.config.cjs
module.exports = {
  apps: [{
    name: 'my-nuxt-app',
    port: '3000',
    exec_mode: 'cluster',
    instances: 'max',
    script: './.output/server/index.mjs',
  }],
}

pm2 start ecosystem.config.cjs and you're in cluster mode across all cores.

Docker

A minimal multi-stage image:

FROM node:22-alpine AS build
WORKDIR /app
COPY . .
RUN corepack enable && pnpm install --frozen-lockfile && pnpm build

FROM node:22-alpine
WORKDIR /app
COPY --from=build /app/.output ./.output
EXPOSE 3000
CMD ["node", ".output/server/index.mjs"]

Static hosting

Two flavors:

  1. SSG with SSR content (ssr: true, default). nuxt generate prerenders your routes and produces 200.html / 404.html as SPA fallbacks for dynamic routes.
  2. Pure CSR SPA (ssr: false). nuxt generate emits a standard index.html that the browser hydrates.

Upload .output/public/ to any static host — S3, Cloudflare Pages, Netlify, Vercel, GitHub Pages.

Serverless / Edge presets

Nuxt ships 15+ Nitro presets. Set one in config…

export default defineNuxtConfig({
  nitro: { preset: 'vercel' },
})

…or via env when you run nuxt build:

NITRO_PRESET=vercel pnpm build
NITRO_PRESET=netlify pnpm build
NITRO_PRESET=cloudflare-pages pnpm build
NITRO_PRESET=deno-deploy pnpm build
NITRO_PRESET=aws-lambda pnpm build

Most managed platforms (Vercel, Netlify, Cloudflare Pages) auto-detect Nuxt and pick a preset for you.

Environment variables

Server-only secrets live on runtimeConfig, overridable with NUXT_* env vars:

NUXT_API_SECRET=prod_secret
NUXT_PUBLIC_API_BASE=https://api.example.com

Public keys go under runtimeConfig.public and ship to the client.

Deploy checklist

  • [ ] pnpm typecheck / pnpm lint / pnpm test green.
  • [ ] pnpm build succeeds locally.
  • [ ] Required env vars set on the platform (NUXT_*, DB URLs, secrets).
  • [ ] routeRules verified — prerender what you can, SSR what you must.
  • [ ] Sensible cache / swr headers for public routes.
  • [ ] Health check endpoint (/healthz) if the platform expects one.
  • [ ] Log collection wired up (console is enough for most platforms).
  • [ ] Error reporting plugin active (vue:error + server error hook).

CDN / Cloudflare gotchas

If you proxy through Cloudflare, disable:

  1. Speed → Content Optimization → Rocket Loader™
  2. Security → Email Address Obfuscation

Both inject scripts that break hydration.

Rollback plan

  • Keep at least two builds warm when deploying to serverless — old chunk URLs need to resolve for tabs open on the previous version. Nuxt's chunk-error handler will hard-reload, but only if the route still responds.
  • Tag releases (git tag v1.2.3) so you can redeploy instantly.

Beyond Node

  • DenoNITRO_PRESET=deno-deploy or deno-server.
  • Bun — works with Node presets today; Bun-native preset is in beta.
  • Workers / Workerdcloudflare-pages, cloudflare-workers presets have first-class routeRules mapping.

Thanks to the preset system, switching runtimes is rarely more than a config change and a fresh NITRO_PRESET. Build once, deploy anywhere — that's the Nuxt promise.