Next.js App Router 的四層快取
Next.js 14 以後的 App Router 有四個獨立的快取層,每一層都有不同的目的和失效策略:
1. Request Memoization(請求記憶化)
在同一個渲染週期(同一次請求期間),如果你呼叫了多次完全相同的 fetch URL,Next.js 會自動去重,只實際發出一次請求。
這讓你可以在不同的 Server Component 中各自取得所需資料,不需要手動傳遞 props,而不用擔心重複網路請求的效能問題。
作用範圍:單次請求的生命週期,請求完成後丟棄。
2. Data Cache(資料快取)
Next.js 的 fetch 函式預設會持久化快取回應,跨越多個請求和部署重新使用。
相當於把 API 或資料庫回應儲存在伺服器端,直到你明確要求更新。
控制方式有三種:
force-cache(預設):無限期快取,除非你重新驗證或 opt-out。
no-store:完全不快取,每次請求都重新取得最新資料(適合需要即時性的資料,如股價、庫存)。
next.revalidate: 秒數:設定重新驗證的間隔,例如 3600 代表每小時重新取得一次。
3. Full Route Cache(完整路由快取)
Next.js 在 build 時把靜態路由的回應(HTML + React Server Component Payload)預先渲染並快取在伺服器上。
適合內容不會頻繁更改的頁面:關於我們、服務介紹、靜態部落格文章。這些頁面的請求不需要任何計算,直接從快取回傳,速度極快。
控制方式:
force-static:強制靜態渲染(使用動態函式如 cookies() 時,預設不能靜態渲染,此選項強制靜態)。
export const dynamic = 'force-dynamic':讓路由完全動態(每次請求重新渲染)。
export const revalidate = 秒數:ISR(Incremental Static Regeneration),定期重新生成靜態快取。
4. Router Cache(路由快取)
這是客戶端的快取,儲存在用戶瀏覽器記憶體中。當用戶在同一個 session 中導向到已訪問過的頁面,Next.js 會從 Router Cache 中直接回傳,不需要重新請求伺服器。
靜態路由的 Router Cache 時間是 5 分鐘,動態路由是 30 秒。
常見快取設定場景
部落格文章頁面(ISR)
export const revalidate = 60
這讓部落格文章頁面每 60 秒重新生成一次。用戶看到的可能是最多 60 秒前的版本,但所有請求都從快取回傳,效能優秀。
管理後台(完全動態)
export const dynamic = 'force-dynamic'
管理後台需要即時資料,不應該快取。force-dynamic 確保每次請求都重新執行。
公開 API 回應(帶 TTL 的快取)
在 fetch 調用時設定 next: { revalidate: 3600 } 讓外部 API 或資料庫的結果快取一小時,避免重複的高成本查詢。
帶有用戶特定資料的頁面
如果頁面包含登入用戶的個人化資料(購物車、個人設定),要用 cookies() 或 headers() 讓路由動態化,同時確保快取不會把 A 用戶的資料快取給 B 用戶看到。
快取失效策略
revalidatePath 和 revalidateTag
在 Server Action 或 API Route 中,你可以主動讓快取失效:
revalidatePath('/blog'):讓特定路徑的 Full Route Cache 失效,下次請求時重新生成。
revalidateTag('posts'):fetch 時可以設定 tag,之後用 revalidateTag 批量失效所有帶這個 tag 的資料快取。
這讓你能建立「按需重新驗證(On-Demand Revalidation)」——例如管理後台發布新文章後,立刻讓部落格頁面的快取失效,用戶馬上看到新文章。
快取除錯
開發環境中,Next.js 預設關閉 Full Route Cache(始終重新渲染),確保你能看到最新的開發變更。
在 next dev 終端機輸出中,你可以看到每個頁面是 「Static(靜態)」「Dynamic(動態)」還是「ISR(增量靜態再生)」的標示,幫助你確認快取設定是否如預期。