部署

恭喜,是时候将应用发布到生产环境了。

您可以选择 使用 Vercel 托管 Next.js,或者通过 Node.js 服务器、Docker 镜像甚至静态 HTML 文件进行自托管。当使用 next start 部署时,所有 Next.js 功能都得到支持。

生产构建

运行 next build 会为生产环境生成优化后的应用版本。系统会根据您的页面创建 HTML、CSS 和 JavaScript 文件。JavaScript 会被 编译,浏览器包会通过 Next.js 编译器 进行 最小化,以实现最佳性能并支持 所有现代浏览器

Next.js 生成的标准化部署输出同时适用于托管和自托管方案。这确保所有功能在两种部署方式下都能得到支持。在下一个主要版本中,我们将把这个输出转换为我们的 构建输出 API 规范

使用 Vercel 托管 Next.js

Vercel 作为 Next.js 的创建者和维护者,为您的 Next.js 应用提供托管基础设施和开发者体验平台。

部署到 Vercel 无需配置,并能提供额外的可扩展性、可用性和全球性能增强。不过,所有 Next.js 功能在自托管时仍然可用。

了解更多关于 Vercel 上的 Next.js免费部署模板 来试用。

自托管

您可以通过三种方式自托管 Next.js:

Node.js 服务器

Next.js 可以部署到任何支持 Node.js 的托管提供商。确保您的 package.json 包含 "build""start" 脚本:

package.json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  }
}

然后运行 npm run build 构建您的应用。最后运行 npm run start 启动 Node.js 服务器。此服务器支持所有 Next.js 功能。

Docker 镜像

Next.js 可以部署到任何支持 Docker 容器的托管提供商。当部署到容器编排平台如 Kubernetes 或在任何云提供商的容器中运行时,可以使用此方法。

  1. 在您的机器上安装 Docker
  2. 克隆我们的示例(或 多环境示例
  3. 构建容器:docker build -t nextjs-docker .
  4. 运行容器:docker run -p 3000:3000 nextjs-docker

通过 Docker 运行的 Next.js 支持所有功能。

静态 HTML 导出

Next.js 支持从静态站点或单页应用 (SPA) 开始,后续可选择升级使用需要服务器的功能。

由于 Next.js 支持 静态导出,它可以部署到任何能提供 HTML/CSS/JS 静态资源的 web 服务器上,包括 AWS S3、Nginx 或 Apache 等工具。

静态导出 方式运行不支持需要服务器的 Next.js 功能。了解更多

须知:

功能

图片优化

通过 next/image 实现的 图片优化 在使用 next start 自托管时无需配置即可工作。如果您希望使用单独的服务优化图片,可以 配置图片加载器 (image loader)

通过 静态导出 也可以使用图片优化,只需在 next.config.js 中定义自定义图片加载器。注意图片是在运行时而非构建时优化的。

须知:

  • 自托管时,考虑安装 sharp 以在生产环境中获得更高效的 图片优化,在项目目录运行 npm install sharp。在 Linux 平台上,sharp 可能需要 额外配置 以防止内存使用过多。
  • 了解 优化图片的缓存行为 及如何配置 TTL。
  • 您也可以 禁用图片优化 同时保留使用 next/image 的其他优势。例如,如果您已自行优化图片。

中间件

中间件 (Middleware) 在使用 next start 自托管时无需配置即可工作。由于需要访问传入请求,它不支持 静态导出

中间件使用的 运行时 (runtime) 是可用 Node.js API 的子集,以确保低延迟,因为它可能运行在应用的每个路由或资源前。此运行时不需要在 "边缘 (edge)" 运行,可在单区域服务器工作。运行多区域中间件需要额外配置和基础设施。

如果您需要添加使用全部 Node.js API 的逻辑(或外部包),可以考虑将此逻辑移至 布局 (layout) 作为 服务端组件 (Server Component)。例如检查 headers重定向 (redirect)。您也可以通过 next.config.js 使用 headers、cookies 或查询参数进行 重定向重写 (rewrite)。如果不可行,还可以使用 自定义服务器 (custom server)

环境变量

Next.js 支持构建时和运行时环境变量。

默认情况下,环境变量仅在服务端可用。要在浏览器中暴露环境变量,必须添加 NEXT_PUBLIC_ 前缀。但这些公共环境变量会在 next build 时内联到 JavaScript 包中。

要读取运行时环境变量,我们推荐使用 getServerSideProps逐步采用应用路由器 (App Router)。通过应用路由器,我们可以在动态渲染期间安全地在服务端读取环境变量。这允许您使用单一的 Docker 镜像,在不同环境中通过不同值进行升级。

import { unstable_noStore as noStore } from 'next/cache';

export default function Component() {
  noStore();
  // cookies()、headers() 和其他动态函数
  // 也会选择动态渲染,使得
  // 此环境变量在运行时被评估
  const value = process.env.MY_VALUE
  ...
}

须知:

  • 您可以使用 register 函数 在服务端启动时运行代码。
  • 我们不推荐使用 runtimeConfig 选项,因为它不适用于独立输出模式。相反,我们推荐 逐步采用 应用路由器。

缓存与 ISR

Next.js 可以缓存响应、生成的静态页面、构建输出以及其他静态资源如图片、字体和脚本。

缓存和重新验证页面(使用增量静态再生 (ISR) 或应用路由器中的新功能)使用 共享缓存。默认情况下,此缓存存储在 Next.js 服务器的文件系统(磁盘)上。自托管时自动生效,同时支持页面路由器和应用路由器。

您可以配置 Next.js 缓存位置,以将缓存页面和数据持久化到持久存储,或在多个容器或 Next.js 应用实例间共享缓存。

自动缓存

  • Next.js 为真正不可变资源设置 Cache-Control 头为 public, max-age=31536000, immutable。此设置不可覆盖。这些不可变文件包含文件名中的 SHA 哈希,因此可以安全地无限期缓存。例如,静态图片导入 (Static Image Imports)。您可以 配置图片的 TTL
  • 增量静态再生 (ISR) 设置 Cache-Control 头为 s-maxage: <revalidate in getStaticProps>, stale-while-revalidate。此重新验证时间在 getStaticProps 函数 中以秒为单位定义。如果设置 revalidate: false,则默认为一年缓存时长。
  • 动态渲染页面设置 Cache-Control 头为 private, no-cache, no-store, max-age=0, must-revalidate 以防止用户特定数据被缓存。这适用于应用路由器和页面路由器。也包括 草稿模式 (Draft Mode)

静态资源

如果您想在不同域名或 CDN 上托管静态资源,可以在 next.config.js 中使用 assetPrefix 配置。Next.js 在获取 JavaScript 或 CSS 文件时会使用此前缀。将资源分离到不同域名的缺点是额外的 DNS 和 TLS 解析时间。

了解更多关于 assetPrefix

配置缓存

默认情况下,生成的缓存资源会存储在内存中(默认为 50mb)和磁盘上。如果您使用 Kubernetes 等容器编排平台托管 Next.js,每个 pod 都会有缓存的副本。为防止显示过时数据(因为默认情况下缓存不在 pod 间共享),您可以配置 Next.js 缓存提供缓存处理程序并禁用内存缓存。

自托管时配置 ISR/数据缓存位置,可以在 next.config.js 中配置自定义处理程序:

next.config.js
module.exports = {
  cacheHandler: require.resolve('./cache-handler.js'),
  cacheMaxMemorySize: 0, // 禁用默认内存缓存
}

然后在项目根目录创建 cache-handler.js,例如:

cache-handler.js
const cache = new Map()

module.exports = class CacheHandler {
  constructor(options) {
    this.options = options
  }

  async get(key) {
    // 可存储在任何地方,如持久存储
    return cache.get(key)
  }

  async set(key, data, ctx) {
    // 可存储在任何地方,如持久存储
    cache.set(key, {
      value: data,
      lastModified: Date.now(),
      tags: ctx.tags,
    })
  }

  async revalidateTag(tag) {
    // 遍历缓存中所有条目
    for (let [key, value] of cache) {
      // 如果值的标签包含指定标签,删除此条目
      if (value.tags.includes(tag)) {
        cache.delete(key)
      }
    }
  }
}

使用自定义缓存处理程序可确保所有托管 Next.js 应用的 pod 间的一致性。例如,您可以将缓存值存储在 Redis 或 AWS S3 等地方。

须知:

  • revalidatePath 是缓存标签 (cache tags) 上的便利层。调用 revalidatePath 会使用页面的特殊默认标签调用 revalidateTag 函数。

构建缓存

Next.js 在 next build 时生成 ID 以识别正在提供的应用版本。相同的构建应被用于启动多个容器。

如果为环境的每个阶段重新构建,需要在容器间使用一致的构建 ID。在 next.config.js 中使用 generateBuildId 命令:

next.config.js
module.exports = {
  generateBuildId: async () => {
    // 可以是任何内容,如最新的 git hash
    return process.env.GIT_HASH
  },
}

版本偏差

Next.js 会自动缓解大多数 版本偏差 (version skew) 的情况,并在检测到不匹配时自动重新加载应用以获取新资源。例如,如果 deploymentId 不匹配,页面间的转换会执行硬导航而非使用预取值。

当应用重新加载时,如果未设计为在页面导航间持久化状态,可能会丢失应用状态。例如,使用 URL 状态或本地存储会在页面刷新后保留状态。但组件状态如 useState 会在这种导航中丢失。

Vercel 为 Next.js 应用提供额外的 偏差保护 (skew protection),确保即使新版本部署后,旧版本客户端仍可访问旧版本的资源和函数。

您可以手动在 next.config.js 中配置 deploymentId 属性,确保每个请求使用 ?dpl 查询字符串或 x-deployment-id 头。

流式传输与 Suspense

Next.js 应用路由器在自托管时支持 流式响应 (streaming responses)。如果使用 Nginx 或类似代理,需要配置禁用缓冲以启用流式传输。

例如,在 Nginx 中设置 X-Accel-Bufferingno 禁用缓冲:

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/:path*{/}?',
        headers: [
          {
            key: 'X-Accel-Buffering',
            value: 'no',
          },
        ],
      },
    ]
  },
}

On this page