Next.js là gì?
Bạn đã học React, nắm được Component, useState, useEffect — rồi đến lúc muốn làm project thật thì ai cũng bảo "dùng Next.js đi". Nhưng mới học React xong, tại sao lại phải học thêm thứ mới?
Trong bài này, chúng ta sẽ tìm hiểu Next.js là gì, tại sao nó tồn tại, khác gì so với React thuần, và khi nào bạn nên chọn Next.js.
Next.js là gì?
Next.js là một React framework mã nguồn mở được phát triển và duy trì bởi Vercel. Ra mắt lần đầu vào tháng 10/2016, Next.js bổ sung những thứ mà React thuần không có sẵn: server-side rendering, static site generation, file-based routing, và nhiều tối ưu hóa hiệu năng tích hợp.
Hình dung đơn giản như thế này:
- React = thư viện UI (như động cơ xe)
- Next.js = React framework đầy đủ (như cái xe đã hoàn thiện — có bánh, có ghế, có vô lăng)
Với React thuần, bạn phải tự lo routing (React Router), SEO, caching, tối ưu ảnh, font... Next.js đã làm sẵn tất cả những thứ đó cho bạn.
Chưa biết React là gì? Xem trước: React là gì? Hướng dẫn ReactJS cho người mới
Mức độ phổ biến của Next.js
- GitHub: hơn 125.000 stars
- npm: hơn 7 triệu lượt tải/tuần
- Công ty dùng Next.js: TikTok, Hulu, GitHub, Nike, Notion, OpenAI, Vercel
- Tại Việt Nam: nhiều startup và công ty product đang chuyển sang Next.js
React vs Next.js — Khác nhau chỗ nào?
| Tính năng | React (Vite) | Next.js |
|---|---|---|
| Rendering | CSR (Client-Side) duy nhất | SSR, SSG, ISR, CSR |
| Routing | Cần cài React Router | File-based routing có sẵn |
| SEO | Kém (HTML trống) | Tốt (HTML đầy đủ từ server) |
| API Routes | Không có | Có sẵn (backend nhỏ) |
| Tối ưu ảnh | Tự xử lý | next/image (tự động) |
| Tối ưu font | Tự xử lý | next/font (tự động) |
| Metadata/SEO | Tự xử lý | generateMetadata() API |
Vấn đề SEO của React thuần
Khi dùng React + Vite, HTML trình duyệt nhận được ban đầu gần như trống:
<!-- React SPA — HTML Google nhận đầu tiên -->
<!DOCTYPE html>
<html>
<body>
<div id="root"></div> <!-- Trống! -->
<script src="/bundle.js"></script> <!-- JS mới render nội dung -->
</body>
</html>
Google crawler phải chờ JavaScript chạy xong mới đọc được nội dung — điều này ảnh hưởng không nhỏ đến SEO.
Với Next.js SSR, server tạo HTML đầy đủ trước khi gửi cho trình duyệt:
<!-- Next.js SSR — HTML Google nhận -->
<!DOCTYPE html>
<html>
<body>
<h1>Next.js là gì?</h1>
<p>Framework React do Vercel phát triển...</p>
<!-- Nội dung đã có sẵn! -->
</body>
</html>
SSR, SSG, ISR là gì?
Đây là điểm mạnh lớn nhất của Next.js — khả năng chọn chiến lược rendering phù hợp cho từng trang.
SSR — Server-Side Rendering (Render phía server)
HTML được tạo mỗi khi có request đến server. Dữ liệu luôn mới nhất, nhưng server phải xử lý nhiều hơn.
// app/tin-tuc/page.tsx — SSR (tạo mới mỗi request)
async function TinTucPage() {
const res = await fetch('https://api.example.com/news', {
cache: 'no-store' // Không cache = server tạo HTML mỗi lần
});
const news = await res.json();
return (
<ul>
{news.map(item => (
<li key={item.id}>{item.title}</li>
))}
</ul>
);
}
Phù hợp với: trang tin tức, e-commerce (giá/tồn kho thay đổi liên tục), dashboard có dữ liệu realtime.
SSG — Static Site Generation (Tạo tĩnh)
HTML được tạo một lần lúc build, lưu thành file tĩnh. Nhanh nhất vì CDN có thể cache.
// app/blog/page.tsx — SSG (tạo lúc build)
async function BlogPage() {
const res = await fetch('https://api.example.com/posts', {
cache: 'force-cache' // Cache = lấy data một lần lúc build
});
const posts = await res.json();
return (
<ul>
{posts.map(post => (
<li key={post.id}>
<a href={`/articles/${post.slug}`}>{post.title}</a>
</li>
))}
</ul>
);
}
Phù hợp với: blog, tài liệu, landing page, portfolio (ít cập nhật).
ISR — Incremental Static Regeneration
Kết hợp tốt nhất của SSG và SSR: tạo file tĩnh nhưng tự động regenerate sau X giây.
// app/san-pham/page.tsx — ISR (tạo tĩnh, cập nhật mỗi giờ)
async function SanPhamPage() {
const res = await fetch('https://api.example.com/products', {
next: { revalidate: 3600 } // Tự regenerate sau 3600 giây (1 giờ)
});
const products = await res.json();
return <DanhSachSanPham products={products} />;
}
Phù hợp với: trang sản phẩm cập nhật không thường xuyên, blog lớn.
App Router — Next.js 13 trở lên
Từ Next.js 13, App Router trở thành chuẩn mới, thay thế Pages Router cũ. App Router dùng thư mục app/ và hỗ trợ React Server Components mặc định.
Cấu trúc thư mục
my-app/
├── app/
│ ├── layout.tsx ← Layout chung cho tất cả trang
│ ├── page.tsx ← Trang chủ (/)
│ ├── about/
│ │ └── page.tsx ← /about
│ ├── blog/
│ │ ├── page.tsx ← /blog
│ │ └── [slug]/
│ │ └── page.tsx ← /blog/bat-ky-slug-nao
│ └── api/
│ └── hello/
│ └── route.ts ← GET /api/hello
├── public/
├── next.config.ts
└── package.json
Các file đặc biệt trong App Router
layout.tsx— Layout dùng chung, không render lại khi chuyển trangpage.tsx— UI của trang, có thể truy cập qua URLloading.tsx— Hiển thị khi trang đang tải (tự động Suspense)error.tsx— Xử lý lỗi (tự động Error Boundary)not-found.tsx— Trang 404
Server Components — Mặc định trong App Router
Trong App Router, mọi component đều là Server Component mặc định. Chúng chạy trên server, không gửi JavaScript xuống client, và có thể dùng async/await trực tiếp:
// app/blog/[slug]/page.tsx — Server Component (mặc định)
// Không cần useEffect để fetch data!
interface Props {
params: { slug: string };
}
export default async function BlogPost({ params }: Props) {
// Fetch data trực tiếp trên server
const post = await getPost(params.slug);
return (
<article>
<h1>{post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
);
}
// SEO metadata tự động
export async function generateMetadata({ params }: Props) {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.excerpt,
};
}
Client Components — Khi cần tương tác
Khi cần useState, useEffect, hay event handler, thêm 'use client' vào đầu file:
'use client'; // Component này chạy trên client
import { useState } from 'react';
export default function NutThich() {
const [liked, setLiked] = useState(false);
return (
<button onClick={() => setLiked(!liked)}>
{liked ? 'Đã thích ❤️' : 'Thích'}
</button>
);
}
Tối ưu hiệu năng tích hợp sẵn
next/image — Tối ưu ảnh tự động
import Image from 'next/image';
export default function Profile() {
return (
<Image
src="/avatar.jpg"
alt="Ảnh đại diện"
width={200}
height={200}
// Tự động: chuyển sang WebP, lazy load, resize theo device
/>
);
}
Tính năng tự động: chuyển đổi sang WebP/AVIF, lazy loading, responsive sizes, tránh CLS (layout shift).
next/font — Tối ưu font chữ
import { Inter } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
// Self-host Google Fonts → không gửi request đến Google
// Không bị layout shift khi font load
});
export default function RootLayout({ children }) {
return (
<html className={inter.className}>
<body>{children}</body>
</html>
);
}
generateMetadata() — SEO tự động
// Tạo metadata động cho từng trang
export async function generateMetadata({ params }) {
const post = await getPost(params.slug);
return {
title: `${post.title} | VietCode`,
description: post.excerpt,
openGraph: {
title: post.title,
images: [post.coverImage],
},
};
}
Khi nào nên dùng Next.js? Khi nào React thuần là đủ?
| Tình huống | Nên dùng |
|---|---|
| Blog, landing page, trang tin tức | Next.js (SSG/SSR) |
| E-commerce, trang sản phẩm | Next.js (ISR/SSR) |
| Website công ty, portfolio | Next.js (SSG) |
| Admin panel, dashboard nội bộ | React + Vite (CSR) |
| SPA không cần SEO | React + Vite (CSR) |
| App realtime (chat, game) | React + Vite (CSR) |
| Prototype nhanh, học tập | Cả hai đều được |
Quy tắc đơn giản: Trang cần Google index? → Dùng Next.js. Tool nội bộ không cần SEO? → React + Vite là đủ.
Muốn so sánh chi tiết hơn? Xem: Vite là gì? So sánh Vite và các công cụ build khác
Tạo project Next.js đầu tiên
# Tạo project với create-next-app (cách khuyến dùng)
npx create-next-app@latest my-nextjs-app
# Trả lời các câu hỏi:
# ✓ TypeScript? → Yes
# ✓ ESLint? → Yes
# ✓ Tailwind CSS? → Yes
# ✓ Thư mục src/? → No
# ✓ App Router? → Yes (khuyến dùng)
# ✓ Turbopack? → Yes
cd my-nextjs-app
npm run dev
# → Mở http://localhost:3000
Cấu trúc thư mục sau khi tạo:
my-nextjs-app/
├── app/
│ ├── layout.tsx ← Root layout
│ ├── page.tsx ← Trang chủ
│ └── globals.css
├── public/
├── next.config.ts
├── tailwind.config.ts
├── tsconfig.json
└── package.json
Chỉnh sửa app/page.tsx để thấy thay đổi ngay lập tức — Next.js hỗ trợ Hot Module Replacement đầy đủ.
Chưa có nền tảng JavaScript? Xem: JavaScript là gì? trước khi bắt đầu.
Next.js trong lộ trình Frontend 2026
Trong lộ trình học Frontend hiện tại, thứ tự học thường là:
- HTML + CSS cơ bản
- JavaScript (ES6+)
- React (Component, State, Props, Hooks)
- Next.js (framework đầy đủ — bước bạn đang ở)
- TypeScript, Testing, Deployment
Next.js không thay thế React — nó mở rộng React. Kiến thức React bạn đã có vẫn hoàn toàn dùng được trong Next.js.
Xem chi tiết lộ trình: Lộ trình học Frontend 2026
Câu hỏi thường gặp (FAQ)
Học Next.js cần biết React trước không?
Có. Next.js xây trên React, nên cần nắm vững Component, Props, useState, useEffect trước. Nếu còn mới với React, hãy xem bài React là gì trước.
Next.js có khó hơn React không?
Phức tạp hơn một chút. Có thêm khái niệm mới: Server Component vs Client Component, chiến lược cache (SSR/SSG/ISR), App Router. Tuy nhiên sau khi quen, việc phát triển nhanh hơn nhiều so với React thuần.
Next.js 14 và Next.js 15 khác gì?
Điểm khác chính: Next.js 15 thay đổi cách cache mặc định (ít auto-cache hơn, dễ đoán hơn), Turbopack thành dev server mặc định (nhanh hơn Webpack), hỗ trợ React 19. Project mới nên dùng Next.js 15.
Next.js và Vite + React khác nhau chỗ nào?
Vite là công cụ build, không phải framework — bạn vẫn phải tự cấu hình routing, SEO, caching. Next.js là framework đầy đủ có tất cả tích hợp sẵn. Với project cần SEO, Next.js là lựa chọn rõ ràng hơn. Xem: Vite là gì?