跳到主要内容

Next.js 部署、自托管与 standalone

Next.js 的部署方式不只是“上 Vercel 就行”这么一句话。

按现在这代文档的说法,部署路线大致可以分成四类:

  • Node.js server
  • Docker / standalone
  • Static export
  • Adapters

不同路线的能力边界差别很大,尤其会影响:

  • SSR
  • Route Handlers
  • Server Actions
  • 图片优化
  • 缓存和 ISR
  • 元信息文件和动态路由

先看最稳的一条线:Node.js server

{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
}
}

这是最完整、最少惊喜的一条线。

适合:

  • 需要完整 Next 能力
  • 有 SSR、Route Handlers、Server Actions
  • 自己控制 Node 运行环境

官方文档也明确写了:Node.js server 部署支持全部 Next.js 特性。

自托管时官方最强调什么

比较重要的一点是:自托管时最好在 Next 服务前面加反向代理,例如 nginx。

原因不是形式问题,而是它能承担:

  • 异常请求过滤
  • 慢连接攻击缓冲
  • 负载和连接限制
  • 一部分缓存与静态资源策略

也就是说,Next 服务更适合专注于渲染和应用逻辑,不适合裸露在最外层承担所有网络边界责任。

output: 'standalone' 是什么

这是很多团队在 Docker 和自托管场景里最常用的一项配置。

import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
output: 'standalone',
};

export default nextConfig;

它依赖 Output File Tracing,把运行生产版本真正需要的文件收出来,生成一个更轻的 .next/standalone 目录。

官方文档里提到几个关键点:

  • .next/standalone 会带上最小运行所需文件
  • 同时会生成一个最小 server.js
  • public.next/static 默认不会自动复制到 standalone 目录
  • 如果需要由这个最小 server 直接服务静态资源,可以手工复制进去

standalone 适合什么场景

很适合:

  • Docker 镜像瘦身
  • 自托管平台
  • 需要把运行时依赖尽量收窄

不代表:

  • 完全不需要理解 Node 运行环境
  • 完全不需要理解静态资源和图片优化如何交付

Docker 场景怎么理解

比较常见的思路是:

  1. 构建阶段执行 next build
  2. 运行阶段只拷贝 .next/standalone.next/staticpublic
  3. 用最小 Node 镜像起 server.js

这样做的价值主要在于:

  • 镜像更小
  • 依赖更少
  • 部署产物边界更清楚

Static export 的边界

如果配置:

const nextConfig = {
output: 'export',
};

那整个项目会被导成静态文件。

这条线适合:

  • 纯静态文档站
  • 纯营销页
  • 完全不需要服务端能力的内容站

但官方文档也讲得很清楚,这条线是有能力上限的。只要项目依赖:

  • SSR
  • Route Handlers
  • Server Actions
  • 动态服务端逻辑

就不适合把它当默认部署方案。

图片优化在自托管里怎么处理

官方文档明确说明:

  • 使用 next start 自托管时,next/image 可以零配置工作
  • 如果不想让 Next 进程自己承担图片优化,也可以自定义 image loader
  • 图片优化是运行时行为,不是构建时一次性做完

所以在自托管场景里,一个常见判断是:

  • 项目规模不大:直接让 Next 进程处理图片优化
  • 图片量很大或资源隔离要求高:拆专门图片服务或自定义 loader

缓存和 ISR 在自托管里要注意什么

只要离开托管平台,缓存就不再是“默认帮忙做好”的那类能力。

要特别留意:

  • ISR 文件缓存放在哪
  • 多实例之间是否共享缓存
  • 写后重验证如何传播
  • 发布时如何避免版本不一致

如果是多实例部署,这块比单机更值得提前设计。

环境变量和版本一致性

部署时通常还要一起看:

  • Node.js 版本
  • React / Next 版本
  • 环境变量注入时机
  • build 时变量和 runtime 变量的区别

只要这里没理顺,就很容易出现:

  • 本地没问题,线上异常
  • build 能过,运行时报错
  • metadata、API、认证回调在不同环境表现不一致

next start、自定义 server、standalone 三者怎么选

next start

最省心,官方主线最完整。

自定义 server

只有在确实需要时才考虑,例如特殊协议、极强定制化入口。

standalone

更偏部署产物优化,不是运行模型替代品。

Adapters 是什么

16 这一代开始,官方把 Adapters API 正式纳入文档体系。

它更适合平台或基础设施层来接,而不是普通业务项目日常直接手写。

可以把它理解成:

  • 给非官方托管平台留一层标准接入面
  • 让平台能读取 Next 构建后的 outputs、路由和产物信息
  • 把部署平台和 Next 构建模型接得更稳

普通应用项目更常见的使用方式通常不是自己写 adapter,而是:

  • 使用目标平台已经提供的 adapter
  • 或选择官方已经验证过的部署路线

Output Types 值得知道什么

较新的 Adapters 文档里,还把 build outputs 拆成了更清楚的类别,例如:

  • outputs.pages
  • outputs.pagesApi
  • outputs.appPages
  • outputs.appRoutes
  • outputs.prerenders
  • outputs.staticFiles
  • outputs.middleware

这对平台开发很重要,对普通业务项目的价值则更多在于理解:Next 的构建产物已经不只是一个模糊的 .next 目录,而是一套有明确分类的输出模型。

部署路线怎么选

1. 需要完整 Next 能力

优先:Node.js server / Docker / standalone

2. 纯静态内容站

可以考虑:output: 'export'

3. 需要落在特定平台

优先看目标平台是否有现成 adapter 或官方支持方案。

自托管最容易忽略的风险

1. 把 Next 直接暴露到公网

缺少反向代理时,网络边界和稳定性压力都会集中到应用进程本身。

2. 以为 standalone 会自动处理一切静态资源

不是。public.next/static 仍然要单独想清楚怎么交付。

3. 低估多实例下的缓存一致性问题

ISR、标签失效、图片优化、构建版本切换都可能受影响。

4. 以为 static export 只是“更轻的部署方式”

实际上它意味着能力边界明显收缩。

一套比较稳的落地顺序

  1. 先判断项目是否真的需要完整服务端能力
  2. 需要的话,优先按 Node.js server 理解
  3. 再决定是否要 standalone + Docker
  4. 自托管时补反向代理、缓存策略、环境变量和实例一致性设计
  5. 如果落特定平台,再看 adapter 方案

推荐继续往下看

  1. Metadata、SEO、sitemap 与 robots
  2. 图片、字体与第三方脚本
  3. 缓存与重验证

参考资料