nextjs.vnEnglish

Trang chủ

Next.js là gì? Frontend hay backend, dùng khi nào

Next.js là một framework React để làm ứng dụng web full-stack: bạn viết giao diện bằng component React, còn Next.js lo phần định tuyến, render trên máy chủ, đóng gói mã và API. Câu hỏi “Next.js là frontend hay backend?” có câu trả lời ngắn: cả hai, trong cùng một dự án. Trang này chứng minh điều đó bằng một ứng dụng nhỏ đã chạy thử, rồi nói khi nào nên dùng.

Mã trên trang này là một ứng dụng chạy được: 8/8 kiểm tra đạt ngày 31/10/2026. Phiên bản đã chạy thử: next@16.4.3, react@19.3.1, typescript@7.0.2, Node.js v26.0.0.

Next.js là gì

Tài liệu Next.js định nghĩa: “Next.js là một framework React để xây dựng ứng dụng web full-stack. Bạn dùng React Component để làm giao diện, và Next.js cho các tính năng và tối ưu bổ sung.” Next.js cũng tự cấu hình các công cụ cấp thấp như bundler và trình biên dịch.

React chỉ là thư viện giao diện; nó không quyết định URL nào mở trang nào, dữ liệu lấy ở đâu, mã được đóng gói ra sao. Trang react.dev khuyên làm ứng dụng mới bằng một framework, và đặt Next.js (App Router) đầu danh sách framework full-stack. Next.js do Vercel duy trì, mã nguồn mở (giấy phép MIT).

Next.js có hai bộ định tuyến: App Router (mới hơn, hỗ trợ Server Components) và Pages Router (bản gốc, vẫn được hỗ trợ). Dự án mới nên dùng App Router; mọi ví dụ trên trang này dùng App Router. Bản ổn định mới nhất trên npm là 16.4.3, theo dữ liệu ngày 31/10/2026.

Phần “backend”: Server Component đọc dữ liệu trên máy chủ

Trong App Router, mọi page và layout mặc định là Server Component: chạy trên máy chủ, trình duyệt chỉ nhận HTML. Vì vậy nó đọc được file, gọi cơ sở dữ liệu, dùng khoá API mà không lộ ra trình duyệt.

Hàm dưới đây đọc một file JSON trên đĩa, việc trình duyệt không làm được. Dòng import 'server-only' làm build lỗi nếu file này lọt vào mã phía trình duyệt. Đã kiểm tra: không file nào trong .next/static (thư mục mã gửi cho trình duyệt) chứa đoạn mã này.

app/lib/posts.ts
import 'server-only'
import { readFile } from 'node:fs/promises'

export type Post = { id: number; title: string }

// Runs only on the server: it reads a file from disk, which a browser cannot do.
export async function getPosts(): Promise<Post[]> {
  const raw = await readFile(process.cwd() + '/data/posts.json', 'utf8')
  return JSON.parse(raw)
}
app/page.tsx
import { getPosts } from './lib/posts'
import LikeButton from './ui/like-button'

// A Server Component (the default): it runs on the server, and the browser gets HTML.
export default async function Page() {
  const posts = await getPosts()
  return (
    <main>
      <h1>Bài viết</h1>
      <ul>
        {posts.map((p) => (
          <li key={p.id}>{p.title}</li>
        ))}
      </ul>
      <LikeButton />
    </main>
  )
}

Phần “frontend”: Client Component chạy trong trình duyệt

Khi cần state, sự kiện click, useEffect hay API của trình duyệt (localStorage, window), bạn đánh dấu file bằng 'use client'. Next.js vẫn render sẵn nó ra HTML (nút hiện “Lượt thích: 0” ngay cả khi tắt JavaScript), rồi gửi mã của nó cho trình duyệt để nút bấm được.

Mẹo theo tài liệu Next.js: giữ phần lớn trang là Server Component, chỉ những mẩu cần tương tác mới là Client Component, để gửi ít JavaScript hơn.

app/ui/like-button.tsx
'use client'
import { useState } from 'react'

// A Client Component: its code is sent to the browser, so it can hold state and handle clicks.
export default function LikeButton() {
  const [likes, setLikes] = useState(0)
  return <button onClick={() => setLikes(likes + 1)}>Lượt thích: {likes}</button>
}

API ngay trong dự án: Route Handler

File route.ts trong thư mục app là một endpoint HTTP dùng Web Request/Response. GET /api/posts dưới đây trả JSON, dùng chung hàm getPosts() với trang. App di động hay hệ thống khác gọi được endpoint này như mọi API.

app/api/posts/route.ts
import { getPosts } from '../../lib/posts'

// A Route Handler: a backend endpoint in the same project. GET /api/posts answers JSON.
export async function GET() {
  return Response.json(await getPosts())
}

Lúc build hay lúc có request

Next.js quyết định từng route render khi nào. Trang / không đọc gì từ request nên được render sẵn một lần lúc next build; Route Handler mặc định không cache, nên chạy lại mỗi request. Đã thử: sửa data/posts.json sau khi build, / vẫn trả danh sách cũ, còn /api/posts trả danh sách mới.

Đây là chỗ người mới hay vấp: trang tĩnh không tự cập nhật khi dữ liệu đổi. Muốn trang theo dữ liệu, hãy dùng revalidate, cache có thời hạn, hoặc render theo request — mỗi cách một trang hướng dẫn riêng.

Cái giá: JavaScript gửi về trình duyệt

Trang mẫu chỉ có một danh sách và một nút, nhưng trình duyệt vẫn tải runtime của React và Next.js. Số đo thật nằm ở mục “Đã kiểm tra” bên dưới (dòng JavaScript cho /, đã nén gzip). Với trang nội dung thuần, đó là chi phí đáng cân nhắc; với ứng dụng có nhiều tương tác, nó được chia đều cho cả ứng dụng.

Khi nào nên dùng Next.js

Đội đã quen React, và trang cần cả nội dung render sẵn (tốt cho SEO, hiện nhanh) lẫn phần tương tác.

Muốn giao diện và API nhỏ nằm chung một dự án, một lần deploy.

Muốn bắt đầu như trang tĩnh rồi thêm tính năng cần máy chủ sau: theo react.dev, các framework được khuyên dùng đều chạy được dạng tĩnh hoặc SPA và bật render phía máy chủ theo từng route, không phải viết lại.

Khi nào cân nhắc thứ khác

Chỉ cần trang tĩnh, không có máy chủ Node.js: Next.js vẫn xuất tĩnh được (output: 'export'), nhưng mất các tính năng cần máy chủ — tài liệu liệt kê Server Actions, Proxy, Incremental Static Regeneration, tối ưu ảnh với loader mặc định, cookies, rewrites, redirects, headers. Khi đó so với một công cụ thuần tĩnh rồi hãy chọn.

Backend lớn phục vụ nhiều loại client, nhiều tác vụ nền: Next.js không kèm cơ sở dữ liệu, ORM hay hàng đợi — bạn tự chọn. Nhận xét của chúng tôi: khi logic nghiệp vụ là phần chính, một backend riêng (NestJS, Laravel, Django…) đứng sau Next.js thường dễ quản lý hơn.

Đội không dùng React: Next.js là framework của React. Các framework khác cũng có mô hình tương tự (Nuxt cho Vue, SvelteKit cho Svelte).

Chạy ở đâu

Theo tài liệu Next.js: chạy như một máy chủ Node.js (next build rồi next start) hoặc container Docker thì có đủ mọi tính năng; xuất tĩnh thì bị giới hạn; ngoài ra có adapter cho từng nền tảng (adapter đã xác minh: Vercel và Bun). Không bắt buộc dùng Vercel — VPS có Node.js là đủ.

Đã chạy Next.js thì nhớ cập nhật bản vá: xem danh sách lỗ hổng và tự kiểm tra phiên bản trang của bạn ở các liên kết bên dưới.

Đã kiểm tra

  • next build: / is prerendered, /api/posts is not: / build time, /api/posts per request
  • GET / with no JavaScript: the posts read on the server are in the HTML: 200 + 3 titles
  • Client Component: the button is already in the HTML, at 0: pre-rendered
  • Client Component: its code is in a script / loads: in a browser chunk
  • server-only module (reads data/posts.json): in no file under .next/static: 0 files
  • Route Handler: GET /api/posts: 200 application/json, 3 posts
  • edit data/posts.json after the build: / keeps its build-time list, /api/posts reads the file again: / old list, /api/posts new list
  • JavaScript the browser loads for / (gzip): 172 KB in 7 files

Chạy lại kiểm tra: bun scripts/guides/verify-intro.ts

Liên quan

Nguồn

Tóm tắt và diễn giải bằng lời của chúng tôi; mã viết lại từ ví dụ trong tài liệu Next.js. Khi có khác biệt, tài liệu Next.js là chuẩn.