Next.js là framework React của Vercel, cung cấp routing dựa trên hệ thống file, React Server Components, streaming SSR, và một tầng cache khai báo (Cache Components) để kiểm soát chính xác phần nào của một route được render tĩnh, phần nào render động.
Dành cho ai? Tài liệu này giả định bạn đã biết React, TypeScript và các khái niệm cơ bản về HTTP/SSR. Nếu bạn chưa có nền tảng lập trình, xem bản không kỹ thuật tại Next.js - Frontend.

Next.js là gì? Vấn đề nó giải quyết

React tự thân chỉ là thư viện UI — nó không có routing, không có cơ chế render phía server, không có data fetching layer chuẩn. Next.js bổ sung:
  • File-based routing qua thư mục app/
  • React Server Components (RSC) — component render trên server, không gửi JS xuống client
  • Streaming SSR — gửi HTML dần theo từng phần sẵn sàng, kết hợp <Suspense>
  • Cache Components — cache khai báo ở mức function/component, thay cho cơ chế cache ẩn của Next.js 13-15
  • Route Handlers, Server Actions — viết backend logic ngay trong cùng codebase
  • Turbopack (ổn định từ v16) — bundler thay thế Webpack, build nhanh hơn 5-10 lần
Next.js 16 dùng App Router (thư mục app/). Pages Router (thư mục pages/) vẫn được hỗ trợ để tương thích ngược nhưng không nên dùng cho dự án mới — tài liệu này chỉ nói về App Router.

So với tự dựng React app thuần


Các khái niệm cốt lõi

App Router — quy ước file trong thư mục app/

Mỗi thư mục trong app/ là một segment URL. File đặc biệt trong thư mục quyết định hành vi: Quy ước đặt tên thư mục:
  • [id] — dynamic segment, đọc bằng params trong component
  • [...slug] — catch-all segment
  • (group) — route group, dùng để tổ chức code mà không ảnh hưởng URL
  • @slot — parallel route, dùng cho UI hiện song song (modal, tab)
Từ Next.js 15, paramssearchParamsPromise — phải await trước khi dùng. Đây là thay đổi hay bị bỏ sót khi migrate từ bản cũ.
generateStaticParams — sinh sẵn danh sách params lúc build:
Với cacheComponents: true, các params không nằm trong danh sách trả về từ generateStaticParams vẫn render được — chỉ khác là render động tại request thay vì phục vụ từ bản build sẵn. export const runtime — chọn runtime cho từng route:
Chọn edge cho các route chỉ đọc/ghi qua fetch (không dùng driver DB cần Node.js) để giảm cold start. proxy.ts (mục bên dưới) từ Next.js 16 mặc định chạy Node.js runtime, không còn Edge Runtime như middleware.ts trước đây.

Components — Server Component là mặc định

Mọi component trong app/Server Component trừ khi có 'use client' ở đầu file.
Lợi ích thực tế: component tái sử dụng ở nhiều nơi (list, dashboard, modal) — sửa một chỗ, mọi nơi dùng nó cập nhật theo. Không khác gì component pattern trong React thuần, chỉ khác ở chỗ mặc định chạy trên server.

Server vs Client Components

Đây là ranh giới quan trọng nhất khi thiết kế component tree trong App Router.

Server Component

  • Không có 'use client'
  • async/await trực tiếp trong component, gọi DB/API an toàn
  • Không dùng được useState, useEffect, event handler
  • Không gửi JS xuống bundle client

Client Component

  • Bắt đầu bằng 'use client'
  • Dùng được hook (useState, useEffect), event handler, browser API
  • Vẫn được prerender HTML lần đầu (không phải CSR thuần)
  • Tăng kích thước JS bundle gửi về client
'use client' áp dụng cho cả cây con của component đó. Đặt boundary càng sâu càng tốt (component tương tác nhỏ nhất) để giữ phần lớn cây component ở Server, giảm JS bundle.

Layout — khung dùng chung, không remount khi điều hướng

layout.tsx giữ nguyên state và không re-render khi chuyển route con — chỉ children (nội dung page.tsx) thay đổi. Đây là lý do sidebar/header không bị “nháy” khi chuyển trang.

loading.tsx và error.tsx — trạng thái tải và lỗi theo từng route

Next.js tự bọc page.tsx trong một <Suspense> ngầm định nếu có loading.tsx cùng cấp, và trong một error boundary nếu có error.tsx.
reset() chạy lại render của segment bị lỗi mà không cần reload cả trang. Nếu lỗi xảy ra ở layout.tsx gốc (không có error.tsx nào bắt được), Next.js rơi xuống app/global-error.tsx — file này phải tự bọc cả thẻ <html>/<body> vì nó thay thế luôn root layout.

Metadata, Image, Font — tối ưu tích hợp sẵn

Metadata API thay thế việc tự viết thẻ <head> — dùng export const metadata (tĩnh) hoặc generateMetadata (động, cần data):
next/image tự động resize, chuyển định dạng (WebP/AVIF), và lazy-load ảnh:
next/font tự host font (Google Fonts hoặc font cục bộ), loại bỏ layout shift khi font load xong:

Route Handlers — backend API trong app/api/

Route Handlers thay thế API Routes của Pages Router (pages/api/*.ts). Đặt trong route.ts, export theo tên HTTP method.
Khi nào dùng Route Handler thay vì gọi thẳng từ Client Component:

Server Actions — mutation gắn trực tiếp vào component

Server Action là một async function chạy trên server, gọi được thẳng từ Client Component hoặc gắn vào <form action={...}> — không cần định nghĩa route riêng như Route Handler.
useActionState (React 19, tích hợp sẵn trong Next.js 16) quản lý pending state và kết quả trả về từ Server Action mà không cần tự viết useState/useEffect cho việc gọi API.
Server Action vẫn hoạt động khi JavaScript chưa load xong (progressive enhancement của <form>) — khác với gọi Route Handler bằng fetch từ Client Component, vốn phụ thuộc hoàn toàn vào JS đã chạy.

Cache Components — mô hình cache của Next.js 16

Đây là thay đổi kiến trúc lớn nhất của bản 16: cache chuyển từ ngầm định (mặc định cache mọi thứ, phải opt-out) sang tường minh (mặc định không cache gì, opt-in bằng 'use cache'). Bật trong next.config.ts:
Không có 'use cache' → route render động ở mọi request, fetch() không tự cache (khác hẳn Next.js 13-15, nơi fetch được cache ngầm định).
Đánh dấu ở mức file, function, hoặc component.
Dùng profile có sẵn hoặc tự định nghĩa stale / revalidate / expire (giây).
Tag cho phép invalidate chính xác entry liên quan, thay vì xóa cache theo cả path.
Khi không tag theo entry cụ thể, dùng revalidatePath để xóa cache theo cả một route:
revalidateTag ưu tiên hơn khi có thể, vì chỉ xóa đúng entry liên quan thay vì cả route.
Bọc phần dynamic trong <Suspense>; phần còn lại của route được prerender tĩnh và phục vụ ngay lập tức, phần trong Suspense stream sau.
Self-host nhiều instance: use cache mặc định lưu in-memory theo từng instance. Nếu chạy nhiều container/pod, cần cấu hình use cache: remote với cache handler dùng chung (Redis, v.v.) để tránh mỗi instance trả dữ liệu cache khác nhau.
Route segment config cũ (Next.js 13-15) — không dùng nữa khi bật cacheComponents: Nếu đang đọc code base cũ (Next.js 13-15) thấy các export này, đó là dấu hiệu dự án chưa migrate sang Cache Components.

Middleware → proxy.ts

Next.js 16 đổi tên middleware.ts thành proxy.ts (export proxy thay vì middleware) để làm rõ đây là lớp chặn request trước khi route render — không phải nơi đặt business logic.
middleware.ts vẫn chạy được (deprecated, có warning). Runtime cũng đổi: proxy.ts chạy trên Node.js runtime thay vì Edge Runtime mặc định trước đây — ảnh hưởng đến cách xử lý cookie/session trong logic auth. Có codemod hỗ trợ: npx @next/codemod@canary middleware-to-proxy.

Next.js + Claude Code trong workflow lập trình

Khi làm việc với Claude Code trên một dự án Next.js, mô tả càng cụ thể theo đúng API/convention của framework, kết quả càng chính xác — tránh mô tả chung chung để Claude tự đoán giữa Route Handler, Server Action, hay client fetch. Ví dụ yêu cầu rõ ràng, đúng ngữ cảnh kỹ thuật:

Kiến trúc tổng thể


So sánh với các lựa chọn khác


Bắt đầu

Bật Cache Components ngay từ đầu nếu dự án mới:
1

Khởi tạo dự án

create-next-app với flag --app (App Router) và --turbopack.
2

Bật cacheComponents và thiết lập cache profile

Thêm cacheComponents: true, sau đó áp 'use cache' dần cho các route/hàm ít thay đổi trước (landing page, blog).
3

Tách Server/Client Component theo boundary nhỏ nhất

Chỉ đánh dấu 'use client' ở component thực sự cần tương tác/browser API, không đẩy lên cả layout.

Câu hỏi thường gặp

Route Handler (route.ts) là HTTP endpoint thật sự — dùng khi cần một URL cụ thể (webhook, API cho mobile client, tích hợp bên thứ 3 gọi vào).Server Action ('use server') là hàm gọi trực tiếp từ component, không cần định nghĩa route — phù hợp cho mutation gắn liền với 1 form/UI cụ thể, tận dụng progressive enhancement của <form action={...}>.
Không bắt buộc ngay, nhưng nên bật sớm cho dự án mới. Thay đổi lớn nhất: fetch() không còn tự cache mặc định, revalidate export bị loại bỏ (dùng cacheLife trong scope 'use cache' thay thế), dynamic = 'force-static' được thay bằng 'use cache' + cacheLife('max'). Với dự án cũ đang dùng Next.js 13-15, cần audit lại toàn bộ chỗ đang phụ thuộc vào cache ngầm định trước khi bật.
Node.js runtime (khác Edge Runtime mà middleware.ts dùng trước đây). Ảnh hưởng trực tiếp đến logic xử lý cookie/session trong auth — cần kiểm tra lại các thư viện auth (NextAuth/Auth.js, Clerk, v.v.) có tương thích runtime mới không khi migrate.
Từ Next.js 16, Turbopack là bundler mặc định cho cả next devnext build (đã ổn định, không còn gắn cờ --turbo). Webpack vẫn dùng được qua cấu hình, nhưng chỉ nên giữ lại nếu có plugin Webpack chưa có tương đương cho Turbopack.
Có — kết hợp tốt với Turborepo (cùng team Vercel) hoặc Nx. Mỗi app Next.js là một package riêng trong monorepo, chia sẻ code UI/type qua các package nội bộ.

Tóm tắt

App Router

File-based routing trong app/: page.tsx, layout.tsx, route.ts, dynamic segments [id], route groups (name).

Server & Client Components

Server Component mặc định (async, fetch trực tiếp). 'use client' chỉ ở boundary tương tác nhỏ nhất.

Cache Components

Cache tường minh: 'use cache', cacheLife, cacheTag/revalidateTag. Partial Prerendering trộn tĩnh và động trong cùng route.

Route Handlers & proxy.ts

Backend nhẹ trong app/api/**/route.ts. proxy.ts (Node.js runtime) chặn request trước khi route render.
Next.js 16 chuyển cache từ ngầm định sang tường minh (Cache Components), ổn định Turbopack, và đổi middleware.ts thành proxy.ts. Đây là bản nâng cấp về tính đúng đắn và hiệu năng hơn là tính năng bề mặt — audit kỹ phần cache khi migrate từ 13-15.