
Trả lời nhanh: Tối ưu Next.js production theo thứ tự hiệu quả: chọn đúng chế độ render cho từng trang (tĩnh được thì tĩnh, ISR cho trang đổi chậm, SSR chỉ khi thật sự cần), bật cache đủ tầng (fetch cache, ISR cache, next/image, CDN cho asset), nén và tối ưu ảnh, rồi mới đến chuyện code. Trên VPS, các tầng cache của Next.js đều sống trên ổ đĩa (.next/cache), ổ nhanh thì cache hit trả trang trong vài mili-giây, revalidate không làm khựng người dùng.
Cùng một codebase Next.js có thể phản hồi 50ms hoặc 2 giây tùy cách vận hành. Phần lớn bài tối ưu trên mạng nói về code; bài này nói phần bị bỏ quên, vận hành production trên máy của chính bạn: render mode, các tầng cache nằm đâu, và đo thế nào để biết mình đang tốt lên hay chỉ đang tin là tốt lên.
- Thứ tự đòn bẩy: render mode đúng > cache đủ tầng > ảnh và nén > tối ưu code
- ISR = trang tĩnh tự làm mới theo chu kỳ, vua của trang sản phẩm/bài viết trên VPS
- Mọi cache Next.js nằm trong .next/cache trên ổ: IOPS quyết định tốc độ hit và revalidate
- Đo trước - sau bằng TTFB và k6/ab đơn giản; không đo là không phải tối ưu, là cầu may
Đòn bẩy 1: Chọn chế độ render cho từng trang
- Static (SSG): trang giới thiệu, chính sách, landing, build ra HTML sẵn, phục vụ tức thì. Mặc định của App Router khi bạn không động chạm dữ liệu động.
- ISR: trang thay đổi chậm, sản phẩm, bài viết, danh mục. Xuất tĩnh + tự làm mới sau
revalidategiây: người dùng luôn nhận bản tĩnh nhanh, máy chỉ dựng lại nền khi hết hạn. Với web bán hàng trên VPS, ISR thường là cú ăn điểm lớn nhất toàn bài. - SSR (dynamic): chỉ cho trang thật sự theo người dùng, giỏ hàng, dashboard. Mỗi trang SSR không cần thiết là một lần đốt CPU và chờ database oan.
Bài tập đáng làm nhất: liệt kê 10 route nhiều traffic, tự hỏi "trang này thật sự cần dựng lại mỗi lượt xem không?", thường 7/10 câu trả lời là không.
Đòn bẩy 2: Hiểu các tầng cache đang nằm trên ổ của bạn
Next.js production cache nhiều thứ vào .next/cache: kết quả fetch, trang ISR, ảnh đã tối ưu của next/image. Ba hệ quả thực dụng:
- Ổ đĩa là đường nóng: mỗi cache hit là một lần đọc ổ, mỗi revalidate là ghi, ổ NVMe latency thấp giúp trang cache trả trong vài ms và revalidate êm không giật.
- Đừng xóa .next/cache khi deploy (script deploy chỉ build đè), xóa là toàn bộ ISR/ảnh phải dựng lại từ đầu, site "lạnh" trong nhiều phút.
- next/image: lần đầu mỗi cỡ ảnh phải resize (ăn CPU + ghi ổ), từ lần hai là đọc cache. Ảnh nguồn nên đã nén sẵn (WebP) để lần đầu nhẹ nhàng.
Đòn bẩy 3: Nén, asset và CDN đúng chỗ
- Caddy phía trước bật nén sẵn (gzip/zstd), kiểm tra response header có content-encoding.
- Asset tĩnh (/_next/static) là immutable, Next.js tự đặt cache header dài hạn, đừng phá.
- Khách thuần Việt Nam + VPS tại Việt Nam: CDN cho asset là tùy chọn, không phải bắt buộc, origin gần sẵn rồi. Cần chống lưu lượng đột biến hoặc có khách quốc tế thì bật Cloudflare miễn phí trước origin.
Đo trước - sau: 10 phút, khỏi cãi nhau bằng cảm giác
# TTFB tung buoc, chay 5 lan lay trung binh
curl -o /dev/null -s -w "%{time_starttransfer}n" https://ten-mien.vn/
# chiu tai don gian bang ab (100 request, 10 dong thoi)
ab -n 100 -c 10 https://ten-mien.vn/Ghi số trước khi sửa, sửa một thứ, đo lại. Trang ISR/tĩnh khỏe mạnh trên VPS NVMe: TTFB ổn định dưới ~100ms từ mạng Việt Nam. Số nhảy múa theo giờ → nhìn sang database, steal time CPU, hoặc ổ đĩa trước khi nghi ngờ code.
Checklist chốt trước khi khoe site nhanh
- Route nhiều traffic đã đúng render mode (tĩnh/ISR tối đa, SSR tối thiểu)
- revalidate đặt theo nhịp thay đổi thật của dữ liệu (60s cho giá, 3600s cho bài viết...)
- Deploy script không xóa .next/cache
- Ảnh nguồn WebP, next/image bật, header nén hoạt động
- Có số TTFB trước-sau lưu lại
- PM2 cluster mode nếu máy nhiều nhân và app CPU-bound
Đo trước và sau, bằng lệnh
# Do thoi gian may chu tra byte dau tien, 10 lan lien tiep
for i in $(seq 1 10); do
curl -o /dev/null -s -w "%{time_starttransfer}\n" https://ten-mien.vn/san-pham/abc
done
# Do tai bang cong cu don gian
ab -n 200 -c 10 https://ten-mien.vn/san-pham/abc
# Xem trang duoc phuc vu tu bo nho dem hay dung lai
curl -sI https://ten-mien.vn/san-pham/abc | grep -i "x-nextjs-cache\|cache-control\|age"Tiêu đề phản hồi cho biết trang lấy từ bộ nhớ đệm hay vừa dựng lại. Giá trị HIT là đang phục vụ bản đã dựng sẵn, đây là thứ bạn muốn thấy với trang sản phẩm và bài viết.
Chọn chế độ hiển thị cho từng loại trang
| Loại trang | Chế độ nên dùng | Thời gian làm mới đề xuất |
|---|---|---|
| Giới thiệu, chính sách, liên hệ | Tĩnh hoàn toàn | Không cần, dựng lại khi triển khai |
| Danh mục sản phẩm | Tĩnh có làm mới định kỳ | 5 tới 15 phút |
| Trang chi tiết sản phẩm | Tĩnh có làm mới định kỳ | 10 tới 60 phút, kèm cơ chế làm mới ngay khi sửa dữ liệu |
| Bài viết, tin tức | Tĩnh có làm mới định kỳ | 60 phút trở lên |
| Giỏ hàng, tài khoản, trang quản trị | Dựng theo từng yêu cầu | Không đệm |
| Kết quả tìm kiếm có nhiều bộ lọc | Dựng theo yêu cầu, đệm ở tầng dữ liệu | Đệm truy vấn thay vì đệm trang |
Với trang thương mại điện tử, kết hợp làm mới định kỳ và làm mới theo yêu cầu là cấu hình đáng giá nhất: khách luôn nhận bản tĩnh nhanh, còn khi nhân viên sửa giá thì gọi một đường dẫn nội bộ để dựng lại đúng trang đó ngay.
Ba việc ở tầng máy chủ ảnh hưởng nhiều hơn tối ưu mã
- Giữ thư mục đệm qua các lần triển khai. Xóa sạch thư mục dựng rồi build lại là mọi trang phải dựng lại từ đầu, và người dùng đầu tiên vào mỗi trang phải chờ. Giữ lại phần đệm giữa các lần triển khai.
- Bật nén ở máy chủ web phía trước thay vì để ứng dụng tự nén. Máy chủ web làm việc này hiệu quả hơn nhiều.
- Đặt tệp tĩnh sau mạng phân phối nội dung. Ảnh và tệp mã nguồn đi qua mạng phân phối, còn trang động vẫn từ máy chủ. Đây là cấu hình đơn giản và hiệu quả nhất cho khách hàng ở nhiều tỉnh thành.
Danh sách kiểm trước khi nói trang đã nhanh
- Thời gian trả byte đầu tiên dưới 200 ms với trang đã có trong bộ nhớ đệm, đo từ mạng Việt Nam.
- Ảnh đầu trang có khai kích thước và được ưu tiên tải sớm, không đặt tải trễ.
- Ba chỉ số Core Web Vitals đo trên người dùng thật đều ở mức đạt, xem trong Search Console.
- Đã thử tải với 10 người truy cập cùng lúc mà thời gian phản hồi không tăng quá gấp đôi.
- Có theo dõi tự động báo khi trang chậm bất thường, thay vì đợi khách phàn nàn.
Câu hỏi thường gặp
ISR khác gì cache thường?
Cache thường hết hạn là người dùng kế tiếp phải chờ dựng trang mới. ISR trả bản cũ ngay lập tức và dựng bản mới ở hậu trường, không ai phải chờ. Đổi lại có độ trễ dữ liệu đúng bằng revalidate, chọn số theo mức chấp nhận của nghiệp vụ.
Có cần Redis cho Next.js không?
App một máy: cache file mặc định là đủ và nhanh (nhất là trên NVMe). Redis đáng cân nhắc khi chạy nhiều instance cần cache chia sẻ, hoặc cache dữ liệu ngoài vòng đời Next.js.
Vì sao trang đầu chậm mà các trang sau nhanh?
Đó là cold cache: lần đầu phải dựng và ghi cache, các lần sau đọc lại. Sau deploy hãy 'hâm nóng' bằng cách curl qua các trang chính, hoặc chấp nhận vài lượt đầu chậm theo thiết kế ISR.
Tối ưu vậy rồi TTFB vẫn cao thì nhìn đâu tiếp?
Theo thứ tự: database (query chậm? thiếu index?), steal time CPU (top), IOPS ổ (fio), rồi mới đến network. Bài IOPS và bài database chậm trong mục liên quan là hai bước kế tiếp tự chẩn.
Bài viết liên quan
- Deploy Next.js lên VPS từ A-Z
- IOPS là gì? Vì sao quyết định tốc độ web/database
- VPS ổ Enterprise U.2 NVMe RAID 10 tại TND
- Cấu hình VPS tối thiểu để Claude Code chạy mượt cả ngày
- VPS Singapore vs VPS Việt Nam: khi nào chọn cái nào (latency, content delivery)
- CPU steal time: kẻ cắp hiệu năng VPS và cách phát hiện
- cPanel/WHM phát hành 5 bản vá khẩn cấp - Hướng dẫn cập nhật VPS an toàn
- PostgreSQL backup tự động trên VPS qua pg_dump + cron + S3
- Caddy server vs Nginx cho dev solo: cái nào dễ setup hơn?



