Skip to main content

Next.js 16.2 升級實錄

4 min read
nextjs-16-2-upgrade-real-world

最近 Next.js 16.2 發佈了(2026/3/18),release notes 裡面寫了一堆效能改善——dev startup 快 87%、rendering 快 25-60%、200+ Turbopack bug fixes。

聽起來很厲害,但數字是官方的環境測出來的,跟你我的專案可能差很多。所以我就拿自己的 blog(一個中小型 Next.js App Router 專案,24 routes、Three.js 3D 頁面、Drizzle ORM + Postgres)來實際升級,看看到底有沒有感覺。


TL;DR

先上結論,懶得看全文的可以直接看這張表:

指標16.1.216.2.0變化
Build time(3 次平均)9.64s8.57s-11.1%
.next 目錄大小29MB31MB+6.9%
Dev cold start(3 次平均)1285ms559ms-56.5% ✓✓✓
測試(80 tests)549ms451ms-17.9%

Dev cold start 的改善最誇張,直接砍半還多。Build time 也有穩定的 11% 改善。.next 大了一點點但可以接受。

值不值得升?值得,尤其如果你每天 next dev 開好幾次的話 (´・ω・`)


1. Next.js 16.2 帶來了什麼

效能改善

  • Dev startup 加速:官方說 ~87% faster(對,你沒看錯,是 87%),主要是 Turbopack 的啟動優化
  • Server Components rendering 加速:他們改了 React 的 JSON.parse reviver 實作方式。原本的 reviver callback 每對 key-value 都會跨越 V8 的 C++/JS boundary,即使是空的 reviver 也會讓 JSON.parse 慢 4 倍。新的做法是先 JSON.parse() 再用純 JS 遞迴走一遍,實測 rendering 快 25-60%
  • ImageResponse 加速:基本圖片 2x,複雜圖片最高 20x faster

開發體驗改善

  • Server Function Logging:dev 的時候 terminal 會顯示 Server Action 的執行資訊(函式名稱、參數、耗時、檔案位置)。這個超實用,以前 debug Server Action 真的很痛苦
  • Hydration Diff Indicator:hydration mismatch 的 error overlay 現在會用 + Client / - Server 格式清楚標示差異,不用再自己猜哪邊不一樣了
  • Error Cause Chain:error overlay 會顯示完整的 Error.cause chain,最多 5 層
  • --inspect for next start:16.1 支援 next dev --inspect,16.2 延伸到 production server

新 API

  • <Link transitionTypes>:可以傳 View Transition 的 type,做不同方向的 page transition 動畫
  • unstable_catchError():比 error.tsx 更細粒度的 error boundary,可以放在 component tree 的任何位置
  • unstable_retry():error.tsx 的新 prop,比 reset() 更強——會同時 router.refresh() 重新 fetch 資料
  • Adapters API stable:讓部署平台可以自定義 build process

Turbopack(200+ fixes)

  • Server Fast Refresh(server-side 的 HMR)
  • Web Worker Origin 支援
  • Subresource Integrity 支援
  • Dynamic imports 的 tree shaking

AI 相關

  • create-next-app 內建 AGENTS.md
  • Browser log forwarding(把瀏覽器 error 轉發到 terminal,方便 AI agent debug)
  • Dev Server Lock File(防止同時開兩個 dev server)
  • Experimental Agent DevTools

2. 升級過程

改了什麼

其實改動超少,就 package.json 兩行:

- "next": "16.1.2", + "next": "^16.2.0", - "eslint-config-next": "16.1.2", + "eslint-config-next": "^16.2.0",

然後 pnpm install,完事。React 19.2.3、Tailwind v4、Drizzle ORM 這些都不用動。

有沒有踩坑

有,兩個小坑:

坑 1:NextMiddleware 型別變嚴格了

測試裡面 mock auth 函式回傳 null 的寫法:

// 16.1.2 OK,16.2.0 報錯 vi.mocked(auth).mockResolvedValue(null); // TS2345: Argument of type 'null' is not assignable to parameter of type 'NextMiddleware'

修法很簡單,加個 as never

vi.mocked(auth).mockResolvedValue(null as never);

這不是什麼大問題,就是 Next.js 16.2 收緊了 middleware 相關的型別定義。但如果你的測試也有類似的 mock 寫法,升級後可能會遇到。

坑 2:新增 react-hooks/set-state-in-effect ESLint 規則

新版 eslint-config-next 加了一條規則,禁止在 useEffect 裡面同步呼叫 setState。我的 ThemeToggle 元件用了經典的 mounted pattern:

// 16.2.0 eslint error: Calling setState synchronously within an effect // can trigger cascading renders useEffect(() => { setMounted(true); }, []);

改用 useSyncExternalStore 就好了:

const emptySubscribe = () => () => {}; const mounted = useSyncExternalStore(emptySubscribe, () => true, () => false);

這個改法其實更 React-idiomatic——useSyncExternalStore 的第三個參數是 server snapshot(回傳 false),client 回傳 true,完美取代了 useEffect + useState 的 mounted 模式。

說實話,看到這條新 lint rule 我還蠻開心的。之前寫過一篇關於 Factory AI 禁用 useEffect 的文章,裡面提到的 anti-pattern 跟這條規則的精神完全一致——useEffect 裡面 setState 會多觸發一次不必要的 re-render (╯°□°)╯︵ ┻━┻

proxy.ts 相容性

我的 proxy.ts 用了 NextRequest / NextResponse 做 rate limiting,升級後完全不用改,直接通過。next.config.ts 也不用改(我的設定本來就很簡單,只有 images.remotePatterns)。


3. 效能實測比較

測試環境:macOS、Apple Silicon、pnpm、每次測量前都 rm -rf .next 清快取。

Build Time

每個版本跑 3 次 clean build:

次數16.1.216.2.0
#110.545s8.828s
#29.406s8.497s
#38.982s8.393s
平均9.64s8.57s

改善:-11.1%

官方沒有特別宣稱 build time 的改善,但從 Turbopack 的 200+ fixes 來看,bundling 效率確實有提升。11% 在中小型專案已經蠻有感的了,大型專案可能會更明顯。

另外注意到 16.2 的 build output 多了一行 Finished TypeScript in 3.8s,之前沒有這個——看起來 TypeScript 檢查的時間被獨立出來顯示了,debug build 效能更方便。

Dev Cold Start

每個版本跑 3 次 rm -rf .next && next dev

次數16.1.216.2.0
#11395ms (Ready 861ms)670ms (Ready 355ms)
#21088ms (Ready 629ms)511ms (Ready 225ms)
#31373ms (Ready 854ms)496ms (Ready 220ms)
平均1285ms559ms

改善:-56.5%

這個改善是最有感的。官方宣稱 87% faster(在 default application 上),我的專案是 56.5%——沒有到 87% 但也非常顯著。差異可能是因為我的專案有 Three.js 等較大的 dependency。

Next.js 自己報告的 "Ready in" 時間從 ~780ms 降到 ~267ms,這更接近官方的數字。外部測量的時間差異(包含 pnpm 的 overhead)會稀釋一些。

Bundle Size

指標16.1.216.2.0
.next 目錄29MB31MB

大了 2MB(+6.9%),可能是 Turbopack 新功能(SRI support 等)的 runtime code。不是什麼問題。

測試速度

指標16.1.216.2.0
80 tests549ms451ms

快了 17.9%。雖然測試跑的是 Vitest 不是 Next.js 的 build pipeline,但底層的 TypeScript transform 應該也受惠於 Turbopack 的改善。


4. 值不值得升

結論:升,沒有懸念

  1. 升級成本極低:改兩行 package.json,可能遇到一兩個型別/lint 的小調整
  2. 效能改善實質有感:特別是 dev cold start,每天省下的等待時間累積起來很可觀
  3. 新的 DX 功能很實用:Server Function Logging 和 Hydration Diff 這兩個我等很久了
  4. 沒有 breaking changesproxy.ts、App Router、所有 API routes 都不用改

誰特別應該升

  • 每天頻繁重啟 dev server 的人(cold start 改善 50%+ 很有感)
  • 有複雜 Server Components 的專案(rendering 加速 25-60%)
  • 常在 debug hydration mismatch 的人(新的 diff indicator)

技術債提醒

我的專案還在用已經 sunset 的 @vercel/postgres,這次升級刻意沒有一起遷移到 @neondatabase/serverless,保持升級範圍最小化。如果你也還在用 @vercel/postgres,記得排進 backlog——它不會突然壞掉,但官方已經不再維護了。


整體來說,Next.js 16.2 是一個「升了不會痛、升了真的有感」的版本。官方宣稱的效能數字在真實專案上打了點折扣(87% → 56.5% dev startup、50% → 11% build),但方向是對的,而且 DX 的改善是實實在在的。

推薦大家找個空檔升一下,大概 10 分鐘就搞定了 ヽ(✿゚▽゚)ノ