Next.js 提供了做技術 SEO 所需的一切,但幾乎沒有一項是預設開啟的。這是我在每個 App Router 專案上都會過一遍的清單,大致按影響大小排序。
1. 重要內容用服務端渲染
搜尋引擎能執行 JavaScript,但對服務端渲染的 HTML 收錄得更快、更穩定。在 App Router 中,服務端元件是預設選項——把標題、正文和連結放在服務端元件裡,客戶端元件只負責互動,不負責內容。
快速檢測:禁用 JavaScript 開啟頁面,或者執行 curl https://yoursite.com/page。如果響應裡沒有主要文字,第一輪收錄裡也不會有。
2. 設定 metadataBase 和標題範本
在根佈局中:
import type { Metadata } from 'next'
export const metadata: Metadata = {
metadataBase: new URL('https://example.com'),
title: {
default: 'Example Studio — Web Design and Development',
template: '%s — Example Studio',
},
description: 'Websites and products for small teams: design, development and launch.',
openGraph: { siteName: 'Example Studio', type: 'website' },
}metadataBase 會把相對 URL(canonical、Open Graph 圖片)轉成絕對 URL。有了標題範本,子頁面只需設定自己那部分標題。
3. 每個頁面都有獨立的標題和描述
每個需要被收錄的頁面都要有自己的 <title>(約 50–60 個字元,關鍵詞靠前)和 meta description(約 150–160 個字元,寫得讓人想點擊)。動態頁面使用 generateMetadata:
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params
const post = await getPost(slug)
if (!post) return {}
return {
title: post.title,
description: post.excerpt,
alternates: { canonical: `/blog/${post.slug}` },
openGraph: {
type: 'article',
publishedTime: post.date,
images: [{ url: post.cover, width: 1200, height: 630 }],
},
}
}4. Canonical 連結
每個頁面都設定 alternates.canonical。它能防止查詢參數(?utm_source=...)、末尾斜線和備用網域造成的重複內容。選定一種形式——帶不帶 www、帶不帶末尾斜線——然後在託管平台把其他形式重定向過來。
5. Sitemap
app/sitemap.ts 會生成 /sitemap.xml,靜態匯出也支援:
import type { MetadataRoute } from 'next'
import { getAllPosts } from '@/lib/blog'
export const dynamic = 'force-static'
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const base = 'https://example.com'
const posts = await getAllPosts()
return [
{ url: base, changeFrequency: 'monthly', priority: 1 },
...posts.map((post) => ({
url: `${base}/blog/${post.slug}`,
lastModified: post.date,
changeFrequency: 'yearly' as const,
priority: 0.7,
})),
]
}在 Google Search Console 和 Bing 網站管理員工具中各提交一次。如果主要面向國內使用者,也別忘了百度搜尋資源平台。
6. robots.txt
import type { MetadataRoute } from 'next'
export const dynamic = 'force-static'
export default function robots(): MetadataRoute.Robots {
return {
rules: { userAgent: '*', allow: '/' },
sitemap: 'https://example.com/sitemap.xml',
}
}不要用 robots.txt 來阻止頁面被收錄——被遮蔽的頁面仍可能透過外部連結被收錄。應該在頁面的 metadata 中使用 robots: { index: false }。
7. 結構化資料(JSON-LD)
結構化資料幫助搜尋引擎理解頁面是什麼。對於文章,在頁面中渲染一個 script 標籤:
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'BlogPosting',
headline: post.title,
description: post.excerpt,
datePublished: post.date,
image: `https://example.com${post.cover}`,
author: { '@type': 'Person', name: 'Jane Doe', url: 'https://example.com' },
}
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd).replace(/</g, '\\u003c') }}
/>
)對小型企業有用的類型:首頁用 Organization 或 Person,文章用 BlogPosting,深層頁面用 BreadcrumbList,商品頁用 Product。用 Google 的富媒體搜尋結果測試工具驗證。
8. Open Graph 圖片
在領英、X、Slack 和各種聊天軟體裡分享連結時,會用到 Open Graph 標籤。給每個頁面一張 1200×630 像素的圖片。可以在頁面旁邊放一個靜態的 opengraph-image.png,也可以在 opengraph-image.tsx 中用 ImageResponse 生成(靜態匯出時在建置階段生成,所以不能依賴請求資訊)。
9. 多語言網站:真實的 URL 和 hreflang
每種語言都需要自己的 URL,否則搜尋引擎永遠只能看到其中一種。用 localStorage 在客戶端切換語言對訪客沒問題,但 Google 看不到。使用語言路由段——app/[lang]/...——並宣告各語言版本:
alternates: {
canonical: '/en/blog/my-post',
languages: {
en: '/en/blog/my-post',
'zh-CN': '/zh/blog/my-post',
'sr-Latn': '/sr/blog/my-post',
'x-default': '/en/blog/my-post',
},
}每個語言版本都應列出所有其他版本,包括它自己。
10. 內部連結和標題層級
- 每頁一個
<h1>,然後按順序使用<h2>/<h3>。標題是大綱,不是字號。 - 相關頁面之間互相連結,並使用描述性的錨文字("靜態匯出指南",而不是"點擊這裡")。使用
<Link>,確保它們是真正的<a href>元素。 - 重要頁面離首頁不超過三次點擊。
11. Core Web Vitals
速度是排名訊號,更重要的是轉化訊號。用 PageSpeed Insights 測量(實地資料來自真實的 Chrome 使用者),目標是 LCP ≤ 2.5 秒、INP ≤ 200 毫秒、CLS ≤ 0.1。App Router 專案中常見的問題:首屏圖片過大、客戶端 JavaScript 過多,以及字型或未設尺寸的圖片造成的佈局偏移。如果你的網站動畫很多,可以看動畫網站的 Core Web Vitals 優化。
12. 圖片
- 內容圖片寫描述性的
alt,裝飾性圖片用空的alt=""。 - 明確的
width/height或aspect-ratio,防止佈局偏移。 - 使用現代格式(AVIF、WebP)和合適的尺寸。
- 描述性的檔名:
nextjs-sitemap-example.png,而不是IMG_2041.png。
13. 404 和重定向
對不存在的頁面返回真正的 404(App Router 中用 notFound())。移動或重新命名頁面時,從舊 URL 加一個 301 重定向——在靜態匯出中,就是託管平台的 _redirects 規則。
精簡版清單
- 內容放在服務端元件中
- 根佈局中設定
metadataBase和標題範本 - 每個頁面都有獨立的標題、描述和 canonical
-
sitemap.ts和robots.ts,並提交 sitemap - 文章、組織、麵包屑的 JSON-LD
- 每個頁面都有 Open Graph 圖片
- 每種語言一個 URL,並配置 hreflang
- 合理的標題層級和描述性內部連結
- Core Web Vitals 全部達標
- 真正的 404,以及移動頁面的 301
在做靜態網站?閱讀 Next.js 靜態匯出完全指南,瞭解沒有伺服器時哪些地方不一樣。

