Hướng dẫn SEO Next.js: chọn SSG, SSR hoặc ISR, thiết lập metadata và canonical, tạo sitemap.xml, vận hành blog nhận nội dung qua webhook và vẫn đọc được bởi crawler AI.

Trên trang này
Tóm lại
Next.js là một trong những framework React tốt nhất cho SEO vì nó gửi HTML đầy đủ cho crawler thay vì một khung rỗng. Để lên top, hãy dựng sẵn các trang nội dung (static generation hoặc ISR), định nghĩa tiêu đề, mô tả và canonical bằng Metadata API, tạo sitemap.xml và robots.txt từ thư mục app, dùng liên kết thật và mã trạng thái đúng, đồng thời giữ nội dung chính ngoài mã chỉ chạy phía client, vì hầu hết crawler AI không chạy JavaScript.
Muốn tìm hiểu sâu hơn? Hãy hỏi
Bài trắc nghiệm nhanh
SEO có phù hợp với bạn không, và nên bắt đầu như thế nào?
Sorank phù hợp với câu trả lời của bạn
Thử nghiệm trong 3 ngày trên chính website của bạn và xem vị trí của bạn trên Google, ChatGPT và các AI khác.
Bắt đầu dùng thử miễn phí 3 ngày3 ngày miễn phí, sau đó bạn có thể dừng bất cứ lúc nào. Cam kết hoàn tiền trong 90 ngày nếu không có kết quả.
SEO Next.js chủ yếu là việc chọn đúng cho từng route: phần nào được dựng trên máy chủ, phần nào được lưu bộ nhớ đệm và phần nào đi vào HTML trước khi có bất kỳ script nào chạy. Google giải thích trong kiến thức cơ bản về SEO JavaScript rằng nó xử lý ứng dụng JavaScript qua ba giai đoạn (thu thập, dựng, lập chỉ mục) và rằng "dựng phía máy chủ hoặc dựng trước vẫn là một ý tưởng rất tốt". Next.js làm điều đó theo mặc định. Hướng dẫn này bao quát App Router (Next.js 13 trở lên), kèm ghi chú cho Pages Router cũ hơn.
Có. Một ứng dụng React thuần dùng dựng phía client gửi một tệp HTML gần như rỗng và tạo trang trong trình duyệt; công cụ tìm kiếm phải tự dựng nó, và nhiều bot không bao giờ làm việc đó. Next.js dựng React trên máy chủ, nên phản hồi HTML đã chứa sẵn tiêu đề, văn bản, liên kết và metadata. Hướng dẫn về SEO JavaScript của chúng tôi giải thích vì sao khác biệt này quan trọng cho việc lập chỉ mục.
Trong App Router, các thành phần là Server Component theo mặc định. Ngay cả các thành phần được đánh dấu 'use client' cũng được dựng sẵn thành HTML trên máy chủ. Điểm yếu nằm ở dữ liệu: bất cứ thứ gì được tải trong useEffect, hoặc chỉ tải sau một cú nhấp, sẽ không có trong HTML ban đầu. Hãy tải nội dung trong Server Component, và chỉ giữ client component cho phần tương tác.
Next.js cho phép trộn các chế độ theo từng route. Lựa chọn ảnh hưởng đến độ tươi mới của nội dung, tốc độ và những gì crawler nhận được.
| Chế độ | Khi HTML được tạo | Đánh giá SEO | Phù hợp với |
|---|---|---|---|
| Static generation (SSG) | Lúc build | Tốt nhất: HTML đầy đủ, rất nhanh | Trang đích, tài liệu, bài viết lâu dài |
| Incremental Static Regeneration (ISR) | Lúc build, sau đó được làm mới ở chế độ nền hoặc khi có yêu cầu | Tốt nhất cho site lớn hoặc thường xuyên thay đổi | Blog, danh mục sản phẩm, trang CMS |
| Server-side rendering (SSR) | Ở mỗi yêu cầu | Tốt: HTML đầy đủ, phụ thuộc tốc độ máy chủ | Trang cá nhân hóa hoặc thời gian thực |
| Client-side rendering (CSR) | Trong trình duyệt | Yếu: nội dung không hiển thị với hầu hết bot | Bảng điều khiển sau màn hình đăng nhập |
Tài liệu ISR của Next.js liệt kê lợi ích: cập nhật nội dung tĩnh "mà không phải build lại toàn bộ site" và xử lý số lượng lớn trang mà không phải chờ build lâu. Một route có export const revalidate = 3600 sẽ được tạo lại tối đa mỗi giờ một lần; để kiểm soát chính xác hơn, gọi revalidatePath hoặc revalidateTag khi nội dung thay đổi. Lưu ý ISR không hoạt động với xuất tĩnh (output: 'export'). Với các ứng dụng buộc phải giữ dựng phía client, hướng dẫn về SEO cho ứng dụng một trang của chúng tôi trình bày các cách xử lý.
Mẹo
Hãy kiểm tra những gì bot nhận được, không phải những gì trình duyệt của bạn hiển thị: chạy curl trên URL hoặc mở view-source và tìm một câu trong bài viết. Nếu câu đó không có trong HTML thô, nội dung phụ thuộc vào JavaScript.
Metadata API thay thế next/head trong App Router. Theo tài liệu metadata của Next.js, bạn xuất một đối tượng metadata tĩnh từ layout hoặc trang, hoặc một hàm generateMetadata khi giá trị phụ thuộc vào dữ liệu, và Next.js tự tạo các thẻ head. Cả hai chỉ được hỗ trợ trong Server Component.
export async function generateMetadata({ params }) {
const { slug } = await params
const post = await getPost(slug)
return {
title: post.title,
description: post.excerpt,
alternates: { canonical: `/blog/${slug}` },
openGraph: { images: [post.cover] },
}
}Năm quy tắc giúp ngăn phần lớn vấn đề:
Với các trang động, Next.js truyền metadata theo luồng sau những byte đầu tiên để tăng tốc độ dựng. Tài liệu nêu rằng việc truyền theo luồng bị tắt đối với các bot mong đợi metadata trong head, được nhận diện qua user agent (Bingbot, Twitterbot và Slackbot là một vài ví dụ), và tùy chọn htmlLimitedBots cho phép tùy chỉnh danh sách này. Nếu bạn quan tâm đến một crawler chưa nằm trong danh sách, hãy thêm nó vào. Trên Pages Router, tương đương là thành phần Head từ next/head, với thuộc tính key để tránh thẻ trùng lặp.
Cả hai đều là tệp đặc biệt trong thư mục app. Một tệp sitemap.ts xuất ra hàm trả về các URL sẽ thành /sitemap.xml; một tệp robots.ts sẽ thành /robots.txt. tài liệu tham chiếu sitemap ghi rằng tệp này được lưu bộ nhớ đệm theo mặc định và giới hạn của Google là 50.000 URL cho mỗi sitemap; vượt mức đó, generateSitemaps sẽ chia thành nhiều tệp.
import type { MetadataRoute } from 'next'
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const posts = await getPosts()
return posts.map((p) => ({
url: `https://example.com/blog/${p.slug}`,
lastModified: p.updatedAt,
}))
}Chỉ đưa vào các URL canonical, có thể lập chỉ mục và trả về 200, và dùng ngày cập nhật thật trong lastModified. Sitemap cũng nhận alternates.languages cho site đa ngôn ngữ. Trong robots.ts, hãy trỏ đến sitemap và quyết định bot AI nào được phép thu thập site; bài viết về robots.txt cho các crawler AI liệt kê chúng. Thêm về định dạng, xem mục từ điển về sitemap XML.
| Vấn đề | Điều gì xảy ra | Cách sửa |
|---|---|---|
| Điều hướng bằng onClick và router.push | Google chỉ theo dõi các thẻ a có href | Dùng thành phần Link từ next/link, nó render một liên kết thật |
| Thiếu nội dung nhưng vẫn trả về trang 200 | Soft 404 trong Search Console | Gọi notFound() để route trả về mã 404 |
| Chuyển hướng tạm thời cho trang đã chuyển | redirect() gửi mã 307 | Dùng permanentRedirect() hoặc permanent: true trong next.config (308) |
| Dấu gạch chéo cuối không nhất quán | Hai URL cho cùng một trang | Chọn một dạng bằng tùy chọn trailingSlash và giữ canonical nhất quán |
| Bản xem trước hoặc môi trường thử nghiệm bị lập chỉ mục | Các bản sao trùng lặp của site trên Google | Gửi noindex trên các tên miền không phải production |
| Nội dung sau tab được tải khi nhấp | Văn bản không có trong HTML | Dựng toàn bộ nội dung trên máy chủ và ẩn bằng CSS nếu cần |
Các vấn đề này đều làm giảm khả năng thu thập: crawler phải khám phá được từng URL qua liên kết và nhận một mã trạng thái sạch.
Tài liệu Next.js khuyên render JSON-LD thành thẻ script kiểu application/ld+json trực tiếp trong component trang hoặc layout, được tạo từ cùng dữ liệu với trang, và thoát ký tự < trong JSON đã serialize để ngăn chèn mã. Vì được render trên máy chủ, cả Google lẫn crawler AI đều thấy nó trong HTML thô. Dùng Article (hoặc BlogPosting) cho bài viết, Organization trong root layout, BreadcrumbList cho các trang sâu và Product cho thương mại điện tử. Công cụ tạo schema cho bạn một khối khởi đầu hợp lệ, sau đó kiểm tra trang bằng Rich Results Test của Google.
Next.js đi kèm các thành phần xử lý những nguyên nhân thường gặp khiến Core Web Vitals kém:
Hãy đo dữ liệu thực tế, không chỉ điểm phòng thí nghiệm: hướng dẫn về PageSpeed Insights của chúng tôi chỉ cách đọc cả hai.
Một blog Next.js thường có một trong ba dạng: tệp MDX hoặc Markdown trong kho mã (đơn giản, nhưng mỗi bài viết cần một commit và một lần triển khai), một CMS headless (Sanity, Contentful, Strapi, Payload) được gọi trong Server Component, hoặc một webhook xuất bản nhận bài viết từ công cụ bên ngoài. Trong cả ba trường hợp, mẫu SEO đều giống nhau: một route động app/blog/[slug] với generateStaticParams, generateMetadata, ISR, sitemap lấy từ cùng nguồn, và một trang chỉ mục liên kết đến mọi bài viết.
Mẫu webhook tách việc xuất bản khỏi chu kỳ triển khai của bạn. Một Route Handler nhận bài viết, lưu lại, rồi làm mới các trang bị ảnh hưởng:
// app/api/publish/route.ts
import { revalidatePath } from 'next/cache'
export async function POST(request) {
if (request.headers.get('authorization') !== `Bearer ${process.env.PUBLISH_SECRET}`) {
return new Response('Unauthorized', { status: 401 })
}
const article = await request.json()
await savePost(article)
revalidatePath('/blog')
revalidatePath(`/blog/${article.slug}`)
return Response.json({ ok: true })
}Cần chú ý
Bảo vệ endpoint bằng một khóa bí mật, và làm mới đúng đường dẫn công khai. Tài liệu ISR cảnh báo rằng khi có nhiều instance máy chủ và bộ nhớ đệm tệp mặc định, việc làm mới theo yêu cầu chỉ xóa instance nhận lệnh gọi; hãy dùng một bộ xử lý bộ nhớ đệm dùng chung.
Dựng phía máy chủ là điều kiện đầu tiên cho GEO (generative engine optimization). Phân tích tháng 12/2024 của Vercel, The rise of the AI crawler, nhận thấy rằng "hiện không có crawler AI lớn nào dựng JavaScript", kể tên GPTBot, ChatGPT-User, OAI-SearchBot, ClaudeBot và PerplexityBot, và đếm được 569 triệu lượt tải của GPTBot cùng 370 triệu lượt tải của Claude trên mạng lưới của họ trong một tháng. Một trang Next.js dựng sẵn văn bản, tiêu đề và JSON-LD thì tất cả các bot này đều đọc được; còn trang dựng phía client thì không.
Điều kiện thứ hai là nội dung đáng được trích dẫn: các bài viết trả lời một câu hỏi mỗi phần, có nguồn, số liệu và định nghĩa rõ ràng, được xuất bản đều đặn. Đó là phần Sorank, sản phẩm của chúng tôi, tự động hóa. Sorank là phần mềm SEO và GEO chạy theo chế độ autopilot: nó tìm từ khóa của bạn, và trình tạo bài viết blog của nó viết 20, 60 hoặc 120 bài mỗi tháng, kèm nguồn, liên kết nội bộ và hình ảnh. Trên site Next.js, nó kết nối qua webhook tùy chỉnh được mô tả ở trang cài đặt: Route Handler của bạn nhận từng bài viết, lưu lại và làm mới blog. Sau đó theo dõi lượt nhắc đến trong AI kiểm tra mỗi tháng xem ChatGPT, Claude và Gemini có trích dẫn thương hiệu của bạn hay không.

Tóm lại: dựng sẵn mọi trang bạn muốn được tìm thấy, định nghĩa metadata trên máy chủ, và lấy sitemap từ cùng nguồn với nội dung. Next.js cung cấp công cụ; thứ hạng và trích dẫn AI đến từ những gì bạn xuất bản bằng chúng. Để giữ blog Next.js luôn có bài viết, xem các gói của Sorank, từ $49 mỗi tháng và có bản dùng thử miễn phí 3 ngày.
Next.js được xây trên React, nên so sánh ở đây là giữa các cách dựng trang. Một ứng dụng React một trang mặc định được dựng trong trình duyệt và gửi HTML gần như rỗng, trong khi Next.js dựng sẵn các trang trên máy chủ hoặc lúc build. Crawler, kể cả các bot AI không chạy JavaScript, nhận được nội dung đầy đủ từ Next.js mà không cần cấu hình thêm.
Không tự động. Trong App Router, bạn thêm một tệp sitemap.ts vào thư mục app, trả về các URL của bạn, và Next.js phục vụ nó tại /sitemap.xml. Với site lớn, generateSitemaps chia danh sách thành nhiều tệp, vì Google chấp nhận tối đa 50.000 URL cho mỗi sitemap.
Cả hai đều có thể lên top tốt vì đều dựng sẵn HTML. App Router là lựa chọn được khuyến nghị cho dự án mới: Server Component giảm JavaScript phía client, còn Metadata API, sitemap.ts và robots.ts xử lý các tệp SEO một cách tự nhiên. Trên một site Pages Router đang chạy, việc chuyển đổi hiếm khi đáng giá chỉ vì SEO.
HỌ ĐÃ THỬ SORANK TRƯỚC BẠN
