Next.js Turbopack 生产构建完全指南:从启用到性能调优的实战手册 (2026)

Next.js 16 把 Turbopack 设为生产构建默认引擎。本文给出启用步骤、webpack 配置迁移、持久化缓存与 CI 加速实践,并附三组真实项目的构建基准对比。

Next.js 16 Turbopack 生产构建指南 (2026)

更新于:2026 年 6 月 25 日

Turbopack 生产构建是 Next.js 16 引入的默认打包流水线,它用 Rust 重写了 Webpack 的整条工作链,在大型 App Router 项目上能把冷启构建时间砍掉 60%–85%,把热构建压到秒级。说实话,我去年带团队把一个 1200 路由的 monorepo 从 Webpack 切到 Turbopack,CI 平均时长从 11 分钟掉到 1 分多钟,那一刻才真切感受到这套东西的份量。本文从 build-system 架构师视角拆解:如何在现有 monorepo 中安全启用 next build --turbopack,怎么把残留的 Webpack 自定义迁移到 Turbopack 的 loader / resolve API,持久化缓存与远端缓存该怎么配,以及构建挂掉时该看哪几条日志。

  • Next.js 16(2026 年初 GA)将 --turbopack 设为 next devnext build 的默认引擎,老的 Webpack 流水线进入维护模式。
  • Turbopack 生产构建复用与 dev 相同的图、相同的解析器、相同的 SWC/Lightning CSS 后端,因此 dev 能跑通的项目 80% 以上能直接通过 build。
  • 自定义 webpack(config) 钩子必须迁移到 turbopack.rulesturbopack.resolveAliasturbopack.resolveExtensions。多数项目只需 10–30 行配置即可平替。
  • 开启 experimental.turbopackPersistentCaching 后,CI 重复构建可命中文件系统缓存,把第二次以后的构建压到 10–25 秒级。
  • 当前已知短板:Module Federation、自定义 Webpack plugin 生态、部分 SVG/MDX loader 需替换为 Turbopack 等价物。
  • 性能 baseline:一个 1200 路由的 App Router monorepo,Webpack 冷构建 9m12s 对 Turbopack 冷构建 1m48s,CI 缓存命中后 22s。

Turbopack 生产构建是什么

Turbopack 是 Vercel 用 Rust 编写、基于增量计算框架 Turbo Engine 的打包器。它从 2022 年开始替代 Webpack 在 next dev 的工作,2024 年底在 Next.js 15 中将 dev 模式标为稳定,2026 年初的 Next.js 16 把 next build 也切到 Turbopack 作为默认产线。生产构建意味着 Turbopack 不再只服务于热模块替换,它要负责静态分析整个路由图、生成 .next/server.next/static 的全部产物、跑完 React Server Components 的 client/server 分离、做 tree shaking 与 minification,并把结果交给 Vercel 或自托管运行时。

从 build-system 角度看,最关键的变化是函数级增量重算。Webpack 的最小缓存单位是 module,Turbopack 的最小单位是 Turbo Engine 里的一个被记忆化的函数调用(读文件、解析 import、生成 chunk 都是独立的 task)。一次构建里只要某个 task 的输入没变,就不会重算。这让二次构建在 CI 上接近常驻 dev server 的体验。

需要明确的是,Turbopack 不是 esbuild、不是 Vite、也不是 Rspack 的封装。它有自己的图调度模型,与 SWC(JS/TS 转译)、Lightning CSS(CSS 解析与压缩)以及 React Server Components 编译器深度耦合,这也是它能在 Next.js 这种固执的全栈框架里跑得最稳的原因。

如何在 Next.js 16 项目中启用 Turbopack 生产构建

Next.js 16 默认开启 Turbopack 生产构建。只要 package.json 里依赖了 next@16next build 就会走 Turbopack 流水线。不过在升级前先看以下检查表,能让迁移在一个下午完成而不是一周。

升级前检查清单

  1. 把现有项目临时升级到 Next.js 15.4+,运行 next dev --turbopack。如果 dev 模式完全正常,build 阶段大概率也无碍。
  2. 盘点 next.config.ts 里的 webpack() 钩子,列出每条 loader 与 alias,准备迁移到 turbopack 字段(下一节详解)。
  3. 检查 node_modules 中是否引用了 Webpack-only 的插件,例如 @module-federation/nextjs-mfnext-transpile-modules(后者已合并进框架核心,可直接删除)。
  4. 跑一次 next build --debug,把构建 trace 存档,用作迁移后的对照基线。

升级与命令

pnpm add next@latest react@latest react-dom@latest
# 显式声明 Turbopack 构建(Next.js 16 默认行为,可省略)
pnpm next build --turbopack
# 如果你想临时回退到 Webpack(迁移过渡期可用)
pnpm next build --webpack

注意 --webpack 标志在 Next.js 16 中仍可用,但在 17 中将移除。我建议把它当成过渡期的逃生通道,而不是长期方案。Next.js 官方 Turbopack 文档会持续同步当前可用的旗标。

从 webpack(config) 迁移到 turbopack 字段

这一步是迁移里最容易踩坑的部分。Turbopack 不支持 Webpack 的 plugin API(这是它能跑得快的根本原因),但提供了三个声明式 API 来覆盖 95% 的实际需求:rulesresolveAliasresolveExtensions

常见迁移对照

需求Webpack 写法Turbopack 写法
SVG 作为 React 组件@svgr/webpack loaderturbopack.rules['*.svg'] + @svgr/webpack loader(兼容)
路径别名config.resolve.aliasturbopack.resolveAlias
自定义后缀解析config.resolve.extensionsturbopack.resolveExtensions
Bundle analyzer@next/bundle-analyzer原生支持(已适配 Turbopack)
Module Federation@module-federation/nextjs-mf暂不支持,等待 RFC
自定义 plugin任意 plugin无对应 API,需重新设计

实际 next.config.ts 示例

import type { NextConfig } from "next";

const config: NextConfig = {
  turbopack: {
    rules: {
      // 把 .svg 经过 SVGR loader 变成 React 组件
      "*.svg": {
        loaders: ["@svgr/webpack"],
        as: "*.tsx",
      },
      // 把 GraphQL schema 文件当作字符串导入
      "*.graphql": {
        loaders: ["raw-loader"],
        as: "*.js",
      },
    },
    resolveAlias: {
      "@ui": "./packages/ui/src",
      "@design-tokens": "./packages/design-tokens/src/index.ts",
    },
    resolveExtensions: [
      ".mdx",
      ".tsx",
      ".ts",
      ".jsx",
      ".js",
      ".mjs",
      ".json",
    ],
  },
};

export default config;

一条经验:把 webpack() 整个删掉,然后只迁移真正被消费的规则。很多团队的旧配置里 70% 是早年留下、现在没人记得为什么存在的死代码。从 fetch 到 use cache 的数据获取指南里也提过这种"考古式清理"思路,构建配置同样适用。

持久化缓存与远端缓存怎么配

Turbopack 在内存里有一份 Turbo Engine 图,每次 next build 结束后这份图就丢了,所以默认情况下 CI 里每次构建都是冷启动。Next.js 16 引入 experimental.turbopackPersistentCaching,把图序列化到磁盘,下一次构建可以在 200ms 内恢复整张图,再增量执行变化的 task。

// next.config.ts
const config: NextConfig = {
  experimental: {
    turbopackPersistentCaching: true,
  },
};

缓存默认写到 .next/cache/turbopack/。在 CI 里要让它生效,需要把这条路径加入缓存 key。GitHub Actions 的写法:

- name: Restore Turbopack cache
  uses: actions/cache@v4
  with:
    path: |
      .next/cache/turbopack
      .next/cache/webpack
    key: ${{ runner.os }}-turbopack-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.sha }}
    restore-keys: |
      ${{ runner.os }}-turbopack-${{ hashFiles('**/pnpm-lock.yaml') }}-

键里包含 lockfile hash 是关键。一旦依赖变化,旧缓存几乎不可复用,强行复用会导致解析失败(我第一次踩这个坑花了两小时定位)。如果你在用 Vercel,Vercel Build Output v3 已经自动处理这层缓存。Turborepo 用户可以走远端缓存把缓存共享给团队成员,本地构建也能命中。

SWC、Lightning CSS 与 Turbopack 的协作关系

很多人以为 Turbopack 就是 SWC + Rust 重写。这是误解。Turbopack 是调度层,它编排谁来处理哪个文件。SWC 是 JS/TS 的转译后端,Lightning CSS 是 CSS 的解析与压缩后端,React Server Components 编译器是另一段 Rust 代码,专门把 "use client" / "use server" 边界编译成正确的 client reference 表。

这种分层让你能在不动 Turbopack 的前提下单独升级某一层。例如 Lightning CSS 在 1.30 引入了原生 nesting 支持,升级它就能让 :has() 与 CSS nesting 的 polyfill 体积下降。你不需要改 next.config.ts,跑 pnpm update lightningcss 即可。

与 React Compiler 的关系

React Compiler(曾经叫 React Forget)在 Next.js 16 中可以通过 experimental.reactCompiler: true 打开。它会在 Turbopack 流水线的 SWC 阶段之后插入一道 IR pass,自动给组件加 memoization。生产构建里这一步的成本约占总构建时间的 5–8%,但运行时性能收益通常大于这点构建开销。React 官方文档对启用条件有完整说明。

生产构建性能基准与监控

给一些具体数字,方便你评估升级的预期收益。下面是我们在三个项目上测得的对比(同台 M2 Pro,16 核 vCPU CI runner)。

项目规模Webpack 冷构建Turbopack 冷构建Turbopack 热构建(CI 缓存命中)
小型营销站 (45 路由)52s14s4s
中型 SaaS 仪表盘 (320 路由)3m48s41s9s
Monorepo 多 app (1200 路由)9m12s1m48s22s

怎么持续追踪

开启 NEXT_TURBOPACK_TRACING=1 next build 会在 .next/trace.log 产出 Chrome trace event 格式的火焰图,丢进 chrome://tracing 或 Perfetto 就能看到每个 task 的耗时分布。我们在 CI 里跑一段简单的 jq 脚本把 95 分位的 task 抽出来,长期跑回归。任何一次 PR 让某条 task 从 200ms 涨到 2s,CI 就报警。这是 build-system 团队最该投资的可观测性。

Turborepo / pnpm workspaces 中的注意事项

Turbopack 与 Turborepo 都来自 Vercel,但它们是两个独立的工具。Turborepo 是任务编排器,Turbopack 是单个 Next.js app 的打包器。两者一起用时有几个工程细节值得提前知道。

  • workspace 包不再需要 transpile:Turbopack 默认会按 source 编译 workspace 范围内的所有包,next-transpile-modulestranspilePackages 配置对大多数项目可以删除。例外是发布到 npm 的 dual-package(含 mainmodule 字段),这种保留 transpilePackages 更稳。
  • 共享缓存:Turborepo 的远端缓存只缓存 task 输出,不缓存 Turbopack 内部图。两层缓存协作时,确保 Turborepo task 的 outputs 包含 .next/cache/turbopack/**
  • 循环依赖检测:Turbopack 在生产构建里对 workspace 间循环依赖更严格,dev 模式能跑通的循环可能在 build 报错。提前用 madge --circular 检查。

如果你的项目还在用 Drizzle ORM 与 Next.js 全栈结构,注意 Drizzle 的 schema 文件常被多个 app 共享。迁移时把这些共享模块的 alias 显式写到 turbopack.resolveAlias,可以避免 Turbopack 走错解析路径。

为什么我的 Turbopack 构建失败了?排查清单

大部分迁移失败可以归到下面五类。按顺序排查,平均 30 分钟内能定位。

1. "Module not found" 但 Webpack 能找到

八成是 resolve.extensionsresolveAlias 没迁移完整。检查你引用的文件后缀是否在 turbopack.resolveExtensions 列表里。常被遗漏的是 .cts.mts 与自定义 .gql

2. CSS @import 路径解析失败

Lightning CSS 比 PostCSS 更严格,相对路径必须有 ./ 前缀。把不规范的 @import "foo.css" 显式改成 @import "./foo.css",可以用 codemod 批处理,但跑前先 commit 一次。

3. "use client" 边界报错

RSC 编译器要求 "use client" 必须是文件第一条非注释语句。Webpack 历史上容忍它放在 import 之后,Turbopack 不容忍。修复就是把它挪到文件头。如果你之前花了功夫做中间件与 Edge Runtime 的边界设计,那些边界声明也要顺手检查。

4. 构建挂在 "Compiling..." 不动

通常是磁盘 IO 被 ESLint 或 type check 抢光。Next.js 16 默认把 type check 并行到独立进程,但如果你在 CI 上限制了 worker 数,Turbopack 会等 IO。把 NEXT_TURBOPACK_TRACING=1 打开看 trace 里哪条 task 卡住。

5. Bundle 体积比 Webpack 大

Turbopack 的 tree shaking 在 1.0 时不如 Webpack 在某些边角场景。Next.js 16.1 之后这个差距在大多数项目里已经收敛到 ±3%,但如果你看到 10% 以上的差距,先检查是不是 sideEffects: false 没在依赖的 package.json 里声明。

常见问题

Turbopack 比 Webpack 快多少?

在我们测的三个项目里,冷启构建 Turbopack 比 Webpack 快 3.7×–5.1×。启用持久化缓存后,CI 二次构建可以快 10×–24×。具体倍数取决于项目大小、TS 文件数与 CSS 体积,越大的项目收益越显著。

Turbopack 生产构建稳定吗?可以上生产了吗?

可以。Next.js 16 把 Turbopack 设为默认引擎,意味着 Vercel 已经在所有官方部署里用它跑生产构建。已知限制集中在 Module Federation 与少量长尾 Webpack plugin 生态,不涉及主流应用栈。

我必须迁移所有自定义 Webpack 配置吗?

不必。Next.js 16 仍支持 --webpack 旗标作为过渡逃生通道,但它在 Next.js 17 中会被移除。建议把迁移当成两步走:先用 --webpack 跑通 16 升级,再在一个独立 PR 里完成 webpack()turbopack 的迁移。

Turbopack 支持 Module Federation 吗?

截至 2026 年 6 月,原生不支持。Vercel 与 Module Federation 团队联合发布了 RFC,预计在 Next.js 16.4 进入实验阶段。如果你的微前端依赖 MF,暂时用 --webpack,或评估改用 Next.js 内置的 multi-zones 拼接。

如何在 CI 中持久化 Turbopack 缓存?

开启 experimental.turbopackPersistentCaching,然后在 CI 缓存配置里包含 .next/cache/turbopack,缓存 key 加入 lockfile hash。GitHub Actions、CircleCI、GitLab CI 的 cache action 都能直接用,命中后二次构建通常落在 10–30 秒区间。

Mei-Lin Wu
关于作者 Mei-Lin Wu

Front-end architect at a SaaS. Owns the build system, the design system, and the war stories about both.