Panduan Next.js SEO
cara membuat sebuah Next.js situs dapat di-crawl, dapat diindeks, dan rankable — two routers, rendering modes (SSG/SSR/ISR/server Components), App Router Metadata API, sitemap.ts, robots.ts, next/image, next/tautan, dan mistakes itu quietly break ini.
Bahasa
Next.js solves hardest JavaScript SEO masalah oleh default — jika Anda gunakan ini right. App Router's server Components dan SSG/ISR put konten di HTML so there's no render-queue delay; native Metadata API resolves judul, canonicals, dan Open Graph pada server; sitemap.ts dan robots.ts adalah file conventions. framework gives Anda infrastructure tetapi writes none dari Anda tags untuk Anda. failures adalah predictable: missing metadataBase, no priority pada LCP image, metadata exported dari sebuah Client Component (silently melakukan nothing), dan 404 views returning 200.
TL;DR — Next.js adalah one dari best frameworks untuk SEO when Anda gunakan ini right. bangun Anda halaman pada server atau di bangun time (not entirely di browser), set sebuah unique judul, deskripsi, dan canonical pada setiap halaman, dan gunakan dibangun-di
next/imagedannext/linkcomponents. Next.js gives Anda semua alat — tetapi ini won’t write Anda SEO tags untuk Anda.
What Next.js SEO adalah
Next.js adalah sebuah popular framework dibangun pada React untuk membuat situs web dan web apps. Because ini adalah React di bawah hood, sebuah lot dari halaman dapat menjadi dibangun dengan JavaScript — dan itu’s where SEO pertanyaan come di. Next.js SEO adalah hanya practice dari membuat sure mesin pencari dapat crawl, render, dan indeks sebuah Next.js situs, dan menggunakan framework’s dibangun-di fitur untuk melakukan itu well.
baik news: Next.js dapat bangun Anda halaman ahead dari time atau pada server, so mesin pencari get finished HTML right away. itu menghindari biggest risk dengan JavaScript situs — konten itu hanya menampilkan up setelah scripts run. (untuk broader picture, see JavaScript SEO.)
one big decision: where halaman gets dibangun
When someone — atau Googlebot — menanyakan untuk sebuah halaman, where melakukan finished HTML come dari? Next.js gives Anda sebuah few options:
- di bangun time (Static / SSG) — halaman adalah dibangun ke sebuah plain HTML file ahead dari time. Fast, dan mesin pencari get everything immediately.
- pada server, per permintaan (SSR) — server membangun full halaman setiap time. juga search-friendly, dan selalu fresh.
- sebuah mix (ISR) — static halaman itu refresh pada sebuah timer. sebuah baik default untuk sebagian besar konten.
- di browser (Client-Side / CSR) — server mengirim sebuah near-empty shell dan JavaScript fills ini di. ini adalah risky one untuk SEO; hindari ini untuk Anda main konten.
modern App Router menggunakan server Components oleh default, which berarti Anda konten ends up di HTML automatically — sebuah great starting poin untuk SEO.
sederhana checklist
- Give setiap halaman sebuah unique judul dan deskripsi.
- Set sebuah canonical URL pada setiap halaman.
- gunakan
next/imagecomponent untuk images (ini stops halaman dari jumping sekitar sebagai images muat, dan membuat them smaller). - gunakan
next/linkuntuk tautan internal (ini membuat nyata tautan Google dapat ikuti). - Don’t put Anda main konten behind rendering sisi klien.
- buat sitemap dan sebuah robots.txt (Next.js memiliki sederhana file-based cara untuk melakukan both). Evidence for this claim Next.js App Router supports special metadata files for sitemap and robots output. Scope: Next.js App Router file conventions. Confidence: high · Verified: Next.js: Metadata files
thing people get wrong
“Next.js handles SEO automatically.” (terjemahan) “Next.js handles SEO automatically.” ini doesn’t — not bagian itu penting. Next.js gives Anda machinery (sebuah metadata sistem, sitemap dan robots conventions, sebuah image component), tetapi Anda masih memiliki untuk write Anda judul, deskripsi, dan canonicals yourself. Evidence for this claim Next.js provides metadata APIs, but developers supply page-specific metadata values. Scope: Next.js App Router metadata and generateMetadata APIs. Confidence: high · Verified: Next.js: Metadata and OG images setiap halaman perlu -nya own. sebuah situs where setiap halaman shares one judul, atau memiliki no canonical, adalah paling umum cara sebuah Next.js bangun underperforms.
ingin deeper versi — two routers, Metadata API, metadataBase, LCP
image trick, dan mistakes itu quietly break pengindeksan? Switch untuk Advanced
tab.
TL;DR — Next.js solves hardest JavaScript SEO masalah oleh default when Anda gunakan ini right. App Router defaults untuk server Components dan mendukung SSG/SSR/ISR — semua dari which ship rendered HTML, so there’s no render-queue delay. Set metadata dengan native Metadata API (
metadata/generateMetadata), dan remembermetadataBaseatau Anda canonicals dan OG images go relative. gunakanapp/sitemap.tsdanapp/robots.ts, pre-bangun dynamic routes dengangenerateStaticParams, setprioritypada LCP image, dan pertahankan tautan sebagai nyatanext/linkanchors. halaman Router adalah juga SEO-capable vianext/head. failures adalah predictable — dan sebagian besar dari them aren’t Next.js’s fault, mereka’re yours.
Where Next.js fits
Next.js adalah sebuah React framework, so everything di JavaScript SEO applies. What membuat ini worth -nya own guide adalah itu Next.js ships pertama-class jawaban untuk sebagian besar JS-SEO masalah: server rendering, static generation, sebuah metadata sistem, dan sitemap/robots conventions. hard bagian isn’t whether Google dapat read ini — Google memiliki rendered JavaScript untuk years — ini adalah choosing right rendering mode dan not leaving SEO basics unwired. ini adalah sebuah specialized case dari CMS headless SEO: CMS barely penting, frontend’s rendering decisions decide everything.
One framing untuk pertahankan straight: “this is a Next.js site” (terjemahan) “ini adalah sebuah Next.js situs” doesn’t tell Anda how apa pun single URL adalah delivered. rendering mode, caching, dan server/Client Component boundaries adalah set per route (sometimes per segment) — sebuah project dapat mix sebuah static marketing halaman, sebuah SSR product halaman, dan sebuah Client Component dashboard. Don’t extrapolate one route’s perilaku untuk “the whole app” (terjemahan) “ whole app”; test spesifik URL.
Two routers, two sets dari mechanics
Next.js memiliki two routers, dan mereka handle SEO differently:
- halaman Router ( older model) — data fetching via
getStaticProps/getServerSideProps; metadata via<Head>darinext/head(ataunext-seopackage); no server Components. - App Router (v13+, saat ini dan recommended approach) — React server Components
oleh default; native Metadata API (
metadataexport /generateMetadata); file conventions untukapp/sitemap.tsdanapp/robots.ts;generateStaticParamsuntuk dynamic routes. Evidence for this claim The App Router uses Server Components and supports generateStaticParams plus metadata file conventions. Scope: Current Next.js App Router behavior; route rendering can become dynamic based on APIs used. Confidence: high · Verified: Next.js: Server and Client Components Next.js: generateStaticParams
Both dapat peringkat well. App Router gives Anda sebuah cleaner, integrated metadata sistem (no
next/head juggling) dan server Components out dari box, which adalah why I’d reach untuk ini
pada sebuah baru bangun. tetapi “App Router or you can’t do SEO” (terjemahan) “App Router atau Anda dapat’t melakukan SEO” adalah sebuah myth — plenty dari halaman Router
situs peringkat fine.
rendering modes dan what setiap berarti untuk SEO
How Google handles JavaScript adalah sebuah three-phase pipeline — crawl, lalu sebuah deferred render wave, lalu indeks. “All pages with a 200 HTTP status code are sent to the rendering queue.” (terjemahan) “semua halaman dengan sebuah 200 HTTP kode status adalah dikirim untuk rendering queue.” whole game di Next.js adalah choosing sebuah mode itu puts Anda konten di HTML sebelum itu render wave, so there’s nothing untuk wait untuk. Evidence for this claim Google crawls, renders, and indexes JavaScript pages, and successful pages can enter the rendering queue. Scope: Google Search processing, not a promise that a URL will be indexed. Confidence: high · Verified: Google: JavaScript SEO basics
- Static situs Generation (SSG) — halaman pre-rendered di bangun time. HTML adalah
immediately available dengan no render-queue risk. Best untuk konten itu doesn’t perubahan
setiap minute.
generateStaticParams()(App Router) /getStaticPaths()(halaman Router) decides which dynamic routes get pre-dibangun. - Incremental Static Regeneration (ISR) — static halaman itu revalidate setelah sebuah set
interval (
export const revalidate = 3600). crawler get static HTML dengan rendah TTFB dan konten stays fresh. sebuah strong default — dengan one trap: setelah window expires next permintaan (possibly Googlebot) masih gets stale halaman; fresh versi menyajikan pada permintaan setelah itu. untuk genuinely volatile data (prices, stock), SSR adalah safer. - rendering sisi server (SSR) — HTML rendered per permintaan. crawler get fully
rendered HTML immediately; tradeoff adalah server latency, so watch TTFB dan LCP.
export const dynamic = 'force-dynamic'atau menggunakan permintaan-time APIs (cookies, headers) opts sebuah route ke SSR. - React server Components (App Router default) — render pada server dan kirim HTML;
no JavaScript ships untuk component itself. konten adalah di initial respons dengan no
hydration gap. ini adalah best default untuk SEO. Interactivity lives di Client Components
marked
'use client'. - rendering sisi klien (CSR) — rendered entirely di browser. Googlebot dapat indeks
ini setelah render wave (median ~10 seconds, tetapi 90th percentile stretches untuk
hours), dan lainnya crawler — Bingbot, AI bot, social preview bot — dapat get sebuah empty
halaman. di App Router, CSR adalah opt-di (
'use client'); di halaman Router, hindari fetching primary konten diuseEffect. Don’t gunakan ini untuk konten Anda ingin diperingkatkan.
sebuah reminder I pertahankan coming back untuk: “Googlebot can render it” (terjemahan) “Googlebot dapat render ini” adalah not yang sama sebagai “you should make Googlebot render it.” (terjemahan) “Anda harus membuat Googlebot render ini.” rendering adalah expensive, deferred, dan not universal di seluruh crawler.
Metadata API (App Router)
Metadata API adalah server Component hanya — metadata resolves pada server sebelum
halaman renders, so ini lands di initial HTML. Export metadata dari layout.js atau
page.js:
export const metadata: Metadata = {
title: 'My Page',
description: 'Page description',
}atau, when tags depend pada fetched data, gunakan generateMetadata():
export async function generateMetadata({ params }) {
const post = await getPost(params.slug)
return { title: post.title, description: post.description }
}fields itu penting untuk SEO:
title— mendukung sebuah string, sebuah template ('%s | Brand'), sebuah default, dan sebuah absolute override. atur template once di root layout dan per-halaman judul inherit ini.description,alternates.canonical( correct cara untuk set sebuah canonical di App Router),openGraph(images harus resolve untuk absolute URLs),twitter(juga digunakan oleh LinkedIn dan Slack previews), danrobots(indeks/ikuti plus googleBot-spesifik directives like max-snippet, max-image-preview).metadataBase— diperlukan untuk canonical dan OG image URLs untuk resolve correctly. Forgetting ini adalah single sebagian besar umum Next.js metadata bug: relative URLs leak ke Anda canonical dan Open Graph tags, breaking social previews dan muddying canonical signals.
sebuah judul-template contoh:
// app/layout.tsx
export const metadata: Metadata = {
metadataBase: new URL('https://example.com'),
title: { template: '%s | Brand Name', default: 'Brand Name' },
}
// app/blog/page.tsx
export const metadata: Metadata = { title: 'My Blog Post' }
// Output: <title>My Blog Post | Brand Name</title>Two gotchas. pertama, metadata adalah shallowly merged dari layout untuk halaman — sebuah nested
object like openGraph defined di sebuah child segment replaces parent’s entirely, so
sebuah halaman-tingkat openGraph: { title: 'Home' } quietly drops apa pun openGraph.images set di
layout. kedua — dan ini one bites people — metadata hanya berfungsi di server
Components. Export ini dari sebuah 'use client' file dan ini silently melakukan nothing.
Streaming metadata. untuk dynamically rendered halaman, generateMetadata dapat stream
metadata setelah initial HTML. Googlebot executes JavaScript dan inspects full DOM,
so streamed metadata berfungsi untuk Google. tetapi Next.js detects “HTML-limited bots” (terjemahan) “HTML-limited bot” —
Bingbot, Twitterbot, Slackbot, facebookexternalhit — dan ships them blocking
metadata di <head> instead. Per Next.js docs, “streaming metadata is disabled
for bots and crawlers that expect metadata to be in the <head> tag.” (terjemahan) “streaming metadata adalah disabled
untuk bot dan crawler itu expect metadata untuk menjadi di undefined tag.” ini adalah automatic;
no configuration needed. ini adalah sebuah detail almost no competing guide covers, dan ini adalah why
streaming metadata isn’t sebuah risk untuk bot itu dapat’t wait untuk ini. Prerendered halaman
adalah sebuah berbeda case entirely — metadata there resolves di bangun time, so there’s no
stream untuk worry tentang. ini perilaku adalah versi-spesifik (saat ini sebagai dari Next.js 16.2.10);
re-periksa generateMetadata docs when Anda upgrade. dan because delivery paths differ
oleh entry poin, verify metadata two cara, not one: sebuah direct/production permintaan (curl -I
atau View Source) dan sebuah client-side navigation untuk yang sama route — head dapat update
differently antara two.
Metadata dengan next/head (halaman Router)
pada halaman Router, metadata lives di <Head> dari next/head:
import Head from 'next/head'
export default function Page() {
return (
<>
<Head>
<title>My Page | Brand</title>
<meta name="description" content="Description" />
<link rel="canonical" href="https://example.com/my-page" />
</Head>
{/* page content */}
</>
)
}Set judul dan deskripsi per halaman (not hanya di _app.js), dan put sebuah canonical pada
setiap halaman including paginated variants. next-seo package standardizes ini dengan sebuah
<NextSeo> component dan structured-data helpers. Migrating untuk App Router mostly
berarti trading next/head dan next-seo untuk native metadata export.
melakukan Anda perlu next-seo package? ini adalah sebuah ketiga-party plugin (not bagian dari Next.js
itself) — actively maintained, di v7.2,0 sebagai dari ini writing, not archived. -nya own docs
adalah explicit tentang where ini fits: untuk standard meta tags pada App Router, package’s
README recommends menggunakan Next.js’s dibangun-di generateMetadata/metadata export alih-alih
<NextSeo>; pada halaman Router, <NextSeo> adalah masih sebuah reasonable convenience layer
di atas next/head. one App Router gunakan case package masih covers adalah -nya JSON-LD
helper components (ArticleJsonLd, FAQPageJsonLd, etc. dengan useAppDir), which beberapa
teams prefer di atas hand-rolling <script type="application/ld+json">. Bottom line: pada sebuah baru
App Router bangun, reach untuk native Metadata API pertama — package adalah optional, not sebuah
requirement, dan -nya own maintainers say so.
Sitemaps
di App Router, app/sitemap.ts adalah sebuah file convention itu outputs /sitemap.xml:
import type { MetadataRoute } from 'next'
export default function sitemap(): MetadataRoute.Sitemap {
return [
{ url: 'https://acme.com', lastModified: new Date(), priority: 1 },
{ url: 'https://acme.com/blog', lastModified: new Date(), priority: 0.8 },
]
}untuk besar situs, generateSitemaps() shards ke multiple files (Google’s limit adalah
50 000 URLs per sitemap), setiap disajikan di /.../sitemap/[id].xml. sitemap output juga
mendukung image sitemaps, video sitemaps, dan localized alternates.languages. pada
halaman Router, gunakan next-sitemap atau generate pages/sitemap.xml.js dengan
getServerSideProps.
robots.txt
app/robots.ts generates Anda robots file programmatically:
export default function robots(): MetadataRoute.Robots {
return {
rules: [{ userAgent: '*', allow: '/', disallow: '/private/' }],
sitemap: 'https://acme.com/sitemap.xml',
}
}Per-pengguna-agent aturan dan multiple sitemaps adalah didukung. halaman Router menggunakan sebuah static
public/robots.txt. aturan Anda cannot get wrong pada either router: tidak pernah disallow Anda
JavaScript atau CSS — Google won’t render dari blocked files, dan pada sebuah JS framework itu
dapat blank out halaman entirely.
next/image dan Core Web Vitals
next/image adalah one dari strongest alasan untuk gunakan framework untuk SEO. ini lazy-memuat
below—fold images, memerlukan width/height (atau fill) so ini reserves space dan
mencegah layout shift / CLS, menyajikan WebP/AVIF automatically, dan emits sebuah proper
srcset dari sizes prop. single sebagian besar penting CWV optimization adalah
priority prop pada Anda hero / above—fold image, which preloads ini untuk sebuah faster LCP:
<Image src="/hero.jpg" width={1200} height={630} priority alt="Hero" />Forgetting priority pada LCP image adalah paling umum Next.js CWV mistake — dan CWV
masalah adalah widespread pada nyata Next.js situs (see Stats tab untuk Salt Agency
data). alt adalah diperlukan: empty untuk decorative images, descriptive untuk konten images.
next/tautan dan internal linking
next/link renders standard <a href> anchors di HTML, so Google mengikuti them
normally, dan ini menambahkan client-side navigation plus background prefetching dari di-viewport
tautan di production. SEO aturan adalah sederhana: gunakan next/link untuk tautan internal, dan tidak pernah
substitute sebuah onClick handler atau JavaScript navigation itu doesn’t produce sebuah nyata
anchor — itu tautan aren’t dapat di-crawl. gunakan prefetch={false} pada rendah-nilai tautan untuk save
bandwidth jika Anda perlu.
Dynamic routes dan generateStaticParams
generateStaticParams() tells Next.js which dynamic routes untuk pre-render di bangun time:
// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
const posts = await getPosts()
return posts.map((post) => ({ slug: post.slug }))
}halaman dibangun ini cara adalah fully static HTML — best untuk SEO. Without ini, dynamic routes adalah
rendered pada-demand (SSR) oleh default, which adalah fine tetapi reintroduces server latency. Combine
ini dengan revalidate (ISR) untuk konten itu updates regularly. pastikan semua penting
dynamic URLs adalah di generateStaticParams so nothing waits pada render queue.
data terstruktur (JSON-LD)
Metadata API memiliki no structured-data field — Anda inject JSON-LD sebagai sebuah <script> di sebuah
server Component, which mempertahankan ini di server-rendered HTML di zero client-bundle cost:
const jsonLd = { '@context': 'https://schema.org', '@type': 'Article', /* … */ }
return <script type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />artikel/BlogPosting, BreadcrumbList, Product, dan FAQPage adalah usual jenis. Validate dengan Rich hasil Test setelah apa pun rendering perubahan.
umum Next.js SEO mistakes
Drawn dari nyata audits dan patterns above:
- Missing atau relative canonicals — sering dari sebuah forgotten
metadataBase, which juga breaks OG image URLs. - No
prioritypada LCP image — biggest CWV miss. - 404 views returning
200— gunakan dibangun-dinotFound()untuk mengembalikan nyata status; soft 404s adalah rampant pada Next.js situs. metadataexported dari sebuah Client Component — silently melakukan nothing; ini adalah server Component hanya.- CSR untuk primary konten — fetching critical konten di
useEffectberarti non-Google crawler get empty halaman. - Hash (
#) routing alih-alih History API — itu views aren’t separately dapat di-crawl. - Not exporting
generateStaticParams— dynamic routes render pada-demand alih-alih menjadi pre-dibangun. openGraphoverwritten oleh layout inheritance — child segments replace, not merge.- Blocking JS/CSS di robots.txt atau via sebuah konten Security Policy itu stops Googlebot’s headless Chrome dari memuat scripts — test dengan pemeriksaan URL.
Deployment notes
Next.js adalah dibangun oleh Vercel; hosting there gives tight integration (edge CDN untuk static dan
ISR halaman, baik TTFB) tetapi isn’t diperlukan. Define permanent redirects di redirects() di
next.config.js (mengembalikan 308, atau 301 dengan permanent: true) untuk reliable signaling untuk
crawler, set security dan caching headers via headers(), dan gunakan X-Robots-Tag respons
headers untuk path-based noindex aturan when per-halaman robots metadata adalah awkward.
What untuk periksa where. Cache state, kode status, redirects, dan streamed metadata don’t semua tampilkan up di yang sama test — sebuah route dapat look fine di one periksa dan masih menjadi broken di lainnya:
| periksa | Where untuk look | Why ini dapat differ dari what Anda see rendered |
|---|---|---|
| Cache/revalidation age | respons headers pada sebuah direct permintaan (curl -I) | ISR dapat sajikan stale halaman pada permintaan right setelah window expires |
| Direct HTTP status | curl -I pada production URL, not rendered UI | sebuah “not found” (terjemahan) “tidak ditemukan” view without notFound() masih mengembalikan 200 |
| Redirect perilaku | actual context itu fires ini — redirect() di sebuah server tindakan, sebuah Route Handler, vs. sebuah client onClick | kode status dan respons path differ oleh invocation context, not hanya destination |
| Streamed metadata | Direct permintaan dan client-side navigation untuk yang sama route | Ordinary clients dapat get streamed metadata; HTML-limited bot get blocking metadata; two paths aren’t identical |
| Client-side transitions | Navigate di-app, lalu re-periksa <head> | sebuah route itu’s correct pada pertama muat dapat drift setelah sebuah client transition |
None dari ini adalah guaranteed oleh framework — Next.js gives Anda mechanisms
(redirects(), notFound(), revalidation, streaming), tetapi cache keys, invalidation,
preview state, dan deployment configuration adalah masih Anda responsibility untuk get right dan
untuk test di production, not hanya locally.
One last note pada dynamic rendering — serving prerendered HTML untuk bot dan JavaScript untuk pengguna. Google memiliki deprecated ini sebagai sebuah recommendation: “dynamic rendering was a workaround and not a long-term solution.” (terjemahan) “dynamic rendering adalah sebuah workaround dan not sebuah panjang-istilah solusi.” Anda tidak perlu ini pada Next.js anyway — SSR, SSG, ISR, dan server Components semua put konten di HTML natively. Mention ini so Anda recognize ini di sebuah audit; don’t bangun pada ini.
happy path: App Router + server Components + ISR + Metadata API (dengan
metadataBase) + next/image dengan priority. Get itu right dan sebagian besar dari Next.js SEO adalah
handled.
AI summary
sebuah condensed take pada Advanced versi:
- Next.js solves sebagian besar JS-SEO masalah oleh default — jika Anda pick right rendering mode dan wire up basics. framework gives Anda infrastructure; ini writes none dari Anda tags.
- Two routers: App Router (v13+, recommended) menggunakan server Components dan native
Metadata API; halaman Router menggunakan
next/head/next-seo. Both dapat peringkat. - rendering modes: SSG dan server Components adalah best default (konten di HTML, no render-queue delay). ISR adalah sebuah strong middle ground tetapi memiliki sebuah stale-pada-pertama-permintaan-setelah-revalidation trap. SSR untuk volatile data. CSR adalah risky — non-Google crawler dapat get sebuah empty halaman.
- Metadata API (App Router):
metadataexport ataugenerateMetadata(), server Component hanya.metadataBaseadalah diperlukan atau canonicals dan OG images go relative.openGraphdi sebuah child segment replaces parent’s; metadata di sebuah'use client'file melakukan nothing. - Streaming metadata berfungsi untuk Google tetapi Next.js ships blocking metadata untuk HTML-limited bot (Bingbot, Twitterbot, Slackbot, facebookexternalhit) automatically.
- File conventions:
app/sitemap.ts(dengangenerateSitemaps()untuk 50k+ URLs) danapp/robots.ts. tidak pernah block.js/.css. next/imagemencegah CLS, menyajikan WebP/AVIF; setprioritypada LCP image — top CWV win.next/linkrenders nyata dapat di-crawl<a href>anchors dan prefetches.generateStaticParamspre-membangun dynamic routes; without ini mereka render pada-demand.- JSON-LD adalah injected sebagai sebuah
<script>di sebuah server Component (no Metadata API field). - **
next-seopackage adalah optional, not diperlukan.** ini adalah actively maintained ketiga-party software (v7.2,0, not archived), dan -nya own docs recommend dibangun-digenerateMetadata/metadataexport untuk App Router meta tags —<NextSeo>remains berguna mainly pada halaman Router, atau untuk -nya JSON-LD helper components. - rendering mode adalah set per route, not per project — don’t assume one URL’s perilaku dari lainnya’s; test spesifik route (direct permintaan dan client navigation both).
- Top mistakes: missing
metadataBase, no LCPpriority, 404s returning200(gunakannotFound()),metadatadi sebuah Client Component, CSR primary konten. - Dynamic rendering adalah deprecated — Anda tidak perlu ini; SSR/SSG/ISR/server Components cover ini.
Official documentation
Primary-source documentation dari Next.js dan mesin pencari.
Next.js
- Metadata dan OG Images — App Router metadata sistem,
metadataBase, dan OG image generation. - generateMetadata API Reference — static
metadatavs.generateMetadata, streaming metadata, dan HTML-limited bot list. - sitemap.xml File Convention —
app/sitemap.ts,generateSitemaps(), image/video/localized sitemaps. - robots.txt File Convention —
app/robots.ts, per-pengguna-agent aturan, dan multiple sitemaps. - Learn: SEO — Next.js’s own SEO learning path (introductory; partly predates App Router).
- memahami JavaScript SEO Basics — crawl → render → indeks pipeline, 200-status rendering queue, soft 404s di SPAs, canonicals, dan History API.
- Dynamic rendering (deprecated workaround) — why Google deprecated ini dan what untuk gunakan instead (SSR, static rendering, hydration).
- di-Depth Guide untuk How Google Search berfungsi — where rendering sits di crawl → indeks → sajikan.
Bing / Microsoft
- IndexNow / indexnow.org — push protocol untuk wire untuk sebuah Next.js publish/revalidation event.
Quotes dari source
pada—record statements dari Google, Next.js, dan Google reps. setiap tautan adalah sebuah deep tautan itu jumps untuk quoted passage pada source halaman.
Google — how JavaScript halaman adalah processed
- “All pages with a 200 HTTP status code are sent to the rendering queue, no matter whether JavaScript is present on the page.” (terjemahan) “semua halaman dengan sebuah 200 HTTP kode status adalah dikirim untuk rendering queue, no penting whether JavaScript adalah present pada halaman.” — Google Search Central docs. Jump untuk quote
Google — dynamic rendering adalah deprecated
- “Dynamic rendering was a workaround and not a long-term solution for problems with JavaScript-generated content in search engines.” (terjemahan) “Dynamic rendering adalah sebuah workaround dan not sebuah panjang-istilah solusi untuk masalah dengan JavaScript-generated konten di mesin pencari.” — Google Search Central docs. Jump untuk quote
- “…creates additional complexities and resource requirements.” (terjemahan) “…membuat additional complexities dan resource requirements.” — Google Search Central docs. Jump untuk quote
Next.js — streaming metadata dan HTML-limited bot
- “Streaming metadata is disabled for bots and crawlers that expect metadata to be in the
<head>tag (e.g. Twitterbot, Slackbot, Bingbot).” (terjemahan) “Streaming metadata adalah disabled untuk bot dan crawler itu expect metadata untuk menjadi di undefined tag (e.g. Twitterbot, Slackbot, Bingbot).” — Next.js docs,generateMetadata. Jump untuk quote
John Mueller, Google (via mesin pencari Journal coverage)
- pada growing role dari JavaScript di SEO: “You’re going to run into significantly more JavaScript over the next years than in the 2-ish decades in SEO before. If you’re keen on technical SEO, then past HTML you’re going to need to understand JS more and more.” (terjemahan) “Anda’re going untuk run ke significantly more JavaScript di atas next years daripada di 2-ish decades di SEO sebelum. jika Anda’re keen pada SEO teknis, lalu past HTML Anda’re going untuk perlu untuk memahami JS more dan more.” Read coverage
Next.js SEO checklist
sebuah quick pass untuk confirm sebuah Next.js situs adalah dapat di-crawl, dapat diindeks, dan fast:
- Primary konten renders di HTML pada pertama permintaan (server Components / SSG / SSR / ISR) — not hanya setelah client-side JavaScript.
- No penting halaman depends pada CSR untuk -nya main konten.
- setiap halaman memiliki sebuah unique judul dan deskripsi (gunakan judul
templatedi root layout). -
metadataBaseadalah set di root layout (App Router) so canonicals dan OG images adalah absolute. - sebuah canonical adalah set per halaman via
alternates.canonical(App Router) atau<link rel="canonical">(halaman Router) — not sebuah single shared homepage canonical. -
metadataadalah exported hanya dari server Components, tidak pernah sebuah'use client'file. -
generateStaticParamscovers semua penting dynamic routes. -
app/sitemap.ts(ataunext-sitemap) outputs sebuah saat ini sitemap;generateSitemaps()shards situs di atas 50k URLs. -
app/robots.ts/public/robots.txtexists dan melakukan not block.jsatau.css. - Images gunakan
next/imagedenganwidth/heightataufill; LCP image memilikipriority; semua memilikialt. - tautan internal gunakan
next/link(nyata<a href>) — noonClick-hanya navigation. - 404 views panggil
notFound()dan mengembalikan nyata404(no soft 404s). - JSON-LD adalah injected di sebuah server Component
<head>/body dan passes Rich hasil Test. - Permanent redirects live di
redirects()dinext.config.js(308 /permanent).
mental models
1. rendering mode adalah product. sebelum debugging anything di sebuah Next.js situs, jawaban one pertanyaan: how adalah ini route rendered? server Components / SSG / SSR / ISR put konten di HTML dan adalah rendah-risk; CSR adalah risky one. Almost setiap Next.js SEO masalah resolves untuk ini.
2. framework gives infrastructure, not konten. Next.js ships Metadata API, sitemap/robots conventions, dan Image component — tetapi ini writes none dari Anda judul, deskripsi, canonicals, atau data terstruktur. “Next.js handles SEO automatically” (terjemahan) “Next.js handles SEO automatically” adalah paling expensive myth here.
3. One sumber kebenaran untuk URLs.
Set metadataBase once dan bangun canonicals, OG images, dan sitemap entries dari ini
(absolute, tidak pernah relative). One base URL kills relative-canonical dan broken-OG-image
class dari bugs.
4. server Components pertama, Client Components hanya where needed.
Default untuk server Components so konten dan metadata land di HTML. Reach untuk
'use client' hanya untuk interactivity — dan remember metadata dapat’t come dari sebuah Client
Component.
5. decision aturan untuk rendering. Mostly static (blogs, docs, marketing) → SSG (atau ISR pada sebuah timer). selalu-fresh / volatile (prices, stock) → SSR. perubahan hourly/daily, ingin static speed → ISR (mind stale-pertama-permintaan trap). Interactive, behind sebuah login, not terindeks → CSR adalah fine. Public konten Anda ingin diperingkatkan → tidak pernah CSR.
Next.js SEO — cheat sheet
rendering modes
| Mode | Where HTML adalah dibangun | SEO | Best untuk | Watch out untuk |
|---|---|---|---|---|
| SSG | bangun time → static | ✅ Best | Mostly-static konten | Stale until rebuild |
| server Components | server (App Router default) | ✅ Best | sebagian besar konten | Interactivity perlu Client Components |
| ISR | Static + timed regen | ✅ baik | Hourly/daily konten | pertama permintaan post-revalidation adalah stale |
| SSR | server, per permintaan | ✅ baik | selalu-fresh data | Higher TTFB / infra cost |
| CSR | di browser | ⚠️ Risky | Logged-di dashboards | Empty halaman untuk non-Google crawler |
App Router vs halaman Router
| fitur | App Router | halaman Router |
|---|---|---|
| Metadata | metadata / generateMetadata | next/head + next-seo |
| server Components | Default | Not available |
| Streaming metadata (bot-aware) | Yes | No |
| Sitemap | app/sitemap.ts | next-sitemap / manual |
| Robots | app/robots.ts | public/robots.txt |
| Canonical | alternates.canonical | <link rel="canonical"> di <Head> |
| data fetching | async server Components | getStaticProps / getServerSideProps |
Fast aturan
- Set
metadataBaseatau canonicals/OG images go relative. metadataadalah server Component hanya —'use client'exports melakukan nothing.- Child-segment
openGraphreplaces parent’s (no merge). prioritypada LCP image = top CWV win.- tautan internal =
next/link(nyata<a href>); noonClick-hanya nav. - 404 → panggil
notFound()(nyata404, not soft 404). - tidak pernah disallow
.js/.css. - Streaming metadata → blocking untuk Bingbot, Twitterbot, Slackbot, facebookexternalhit.
- Dynamic rendering: deprecated — gunakan SSR / SSG / ISR / server Components.
Quick memeriksa untuk sebuah Next.js bangun
sebuah few command-line memeriksa sebelum Anda reach untuk sebuah full crawler.
adalah Anda konten di raw HTML (atau hanya setelah JS runs)?
macOS / Linux:
# Raw HTML as the server sends it — the "first fetch", before any client JS
curl -sL -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" \
https://example.com/page/ -o raw.html
# Is your headline actually in the raw HTML? (empty result = CSR / JS-dependent)
grep -o "Your headline text" raw.html
# Did metadataBase do its job? Canonical and OG URLs should be absolute, not relative
grep -iE 'rel="canonical"|og:(url|image)' raw.htmlWindows (PowerShell):
$ua = "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
Invoke-WebRequest -Uri "https://example.com/page/" -UserAgent $ua -OutFile raw.html
Select-String -Path raw.html -Pattern "Your headline text"
Select-String -Path raw.html -Pattern 'rel="canonical"','og:url','og:image'jika headline adalah missing dari raw.html tetapi menampilkan di Anda browser, itu route adalah
client-rendered. jika canonicals atau OG image URLs come out relative, Anda’ve forgotten
metadataBase.
Confirm Anda aren’t blocking JS/CSS (including Next.js _next directory)
macOS / Linux:
curl -sL https://example.com/robots.txt | \
grep -iE "disallow.*\.(js|css)|Disallow:\s*/_next"Windows (PowerShell):
(Invoke-WebRequest "https://example.com/robots.txt").Content |
Select-String -Pattern "Disallow.*\.(js|css)","Disallow:\s*/_next"apa pun match here adalah almost selalu sebuah mistake — Google won’t render dari blocked files. sebuah plain
curl dapat’t run JavaScript, so untuk rendered DOM gunakan pemeriksaan URL’s “View Crawled
Page → rendered HTML.” (terjemahan) “View di-crawl
halaman → rendered HTML.”
alat untuk auditing sebuah Next.js situs
- pemeriksaan URL (Google Search Console) — sumber kebenaran. Run sebuah live test,
lalu view rendered HTML, screenshot, dan halaman resources (what dimuat vs.
what adalah blocked) untuk catch CSR gaps dan blocked
_nextresources. - Rich hasil Test — confirm JSON-LD dibuat ini ke rendered output setelah apa pun rendering perubahan.
- Lighthouse / Chrome DevTools — mengukur LCP, CLS, dan INP; periksa apakah Anda hero
image adalah preloaded (
priority). - Ahrefs situs Audit — melakukan crawl dengan JavaScript rendering, surfacing missing/relative canonicals, broken metadata, rantai pengalihan, dan indexability issues di seluruh frontend.
- Screaming Frog SEO Spider — crawl dengan JS rendering pada/off untuk diff raw vs. rendered HTML, dan bangun pre/post crawl comparisons untuk migrations.
- Bing Webmaster alat — Bing’s pemeriksaan URL dan where IndexNow submissions appear.
Mistakes untuk hindari pada Next.js
Concrete patterns itu quietly break SEO pada nyata Next.js membangun — mencegah ini sebelum mereka ship, alih-alih debugging them setelah sebuah traffic drop.
Shipping without metadataBase di root layout
Why ini adalah wrong: without metadataBase, alternates.canonical dan openGraph.images
resolve untuk relative paths alih-alih absolute URLs. sebuah relative canonical dapat confuse
canonicalization signals, dan relative OG image URLs break tautan previews pada social dan
messaging apps.
What untuk melakukan instead: set metadataBase: new URL('https://example.com') once di
app/layout.tsx dan let setiap halaman inherit ini. periksa ini dengan grep -iE 'rel="canonical"|og:(url|image)' terhadap sebuah raw HTML fetch — URLs seharusnya start dengan https://.
Overwriting sebuah layout’s openGraph dari sebuah child segment
Why ini adalah wrong: metadata merges shallowly dari layout untuk halaman. sebuah halaman-tingkat
openGraph: { title: 'Home' } doesn’t merge dengan layout’s openGraph.images — ini
replaces whole object, silently dropping images.
What untuk melakukan instead: either repeat full openGraph object (images disertakan) di
setiap tingkat itu overrides ini, atau hanya override spesifik top-tingkat metadata fields Anda
actually perlu untuk perubahan, dan leave openGraph untouched where layout’s default adalah fine.
Exporting metadata dari sebuah Client Component
Why ini adalah wrong: Metadata API adalah server Component hanya. tambahkan 'use client' untuk sebuah file
itu juga exports metadata dan export melakukan nothing — no error, no warning, hanya sebuah
halaman dengan no judul atau deskripsi.
What untuk melakukan instead: pertahankan metadata / generateMetadata exports di sebuah plain server
Component file (page.tsx atau layout.tsx without 'use client'). jika sebuah halaman perlu client
interactivity, put itu di sebuah separate child component dan import ini — don’t tambahkan
'use client' untuk file itu owns metadata export.
Fetching primary konten di useEffect (atau relying pada full CSR)
Why ini adalah wrong: konten rendered hanya di browser isn’t di initial HTML. Google akan eventually render ini, tetapi median render delay adalah nyata dan 90th percentile stretches untuk hours — dan non-Google crawler (Bing, social preview bot, sebagian besar AI crawler) sering don’t render JavaScript di semua, so mereka see sebuah empty halaman.
What untuk melakukan instead: default untuk server Components, SSG, ISR, atau SSR untuk anything Anda
ingin terindeks. Reserve 'use client' dan useEffect data-fetching untuk interactive UI itu
doesn’t perlu untuk menjadi dapat di-crawl — sebuah filter widget, not artikel body.
Returning 200 untuk sebuah “not found” (terjemahan) “tidak ditemukan” view
Why ini adalah wrong: rendering sebuah “not found” (terjemahan) “tidak ditemukan” message without calling notFound() mengembalikan sebuah
normal 200 status. itu’s sebuah soft 404 — Google dapat indeks empty-konten halaman alih-alih
recognizing ini sebagai missing, dan soft 404s adalah one dari paling umum dunia nyata Next.js SEO
masalah.
What untuk melakukan instead: panggil dibangun-di notFound() function so route mengembalikan sebuah nyata
404. Confirm dengan curl -I pada sebuah known-missing URL dan periksa kode status directly,
not hanya what renders di browser.
Skipping generateStaticParams pada penting dynamic routes
Why ini adalah wrong: without ini, dynamic routes fall back untuk pada-demand rendering (SSR), which masih berfungsi untuk SEO tetapi menambahkan server latency untuk setiap pertama permintaan untuk itu URL — including Googlebot’s.
What untuk melakukan instead: enumerate URLs itu penting (product halaman, blog posts,
category halaman) di generateStaticParams() so mereka’re pre-dibangun, dan pair ini dengan
revalidate (ISR) untuk konten itu perubahan setelah launch.
Test yourself: Next.js SEO
Five quick pertanyaan pada membuat sebuah Next.js situs dapat di-crawl, dapat diindeks, dan fast. Pick sebuah jawaban untuk setiap, lalu periksa.
Resources worth Anda time
My related writing
- JavaScript SEO: sebuah Definitive Guide — my full guide untuk rendering, DOM parity, canonicals di JS, sitemaps, dan rendering-mode trade-offs itu Next.js sits pada top dari. ini Next.js guide adalah framework-spesifik layer pada top dari ini.
- Beginner’s Guide untuk SEO teknis — where rendering dan crawling fit di bigger picture.
My speaking
- JavaScript SEO — Ungagged 2019 (SlideShare) — my walkthrough dari how frameworks separate frontend dari backend dan how Googlebot renders. (Standing disclaimer: dynamic-rendering recommendation di itu deck adalah now outdated — Google deprecated ini.)
dari sekitar industry
- Metadata dan OG Images (Next.js docs) — App Router metadata sistem,
metadataBase, dan OG image generation. - generateMetadata API Reference (Next.js docs) — static vs. dynamic metadata dan HTML-limited bot / streaming-metadata perilaku.
- sitemap.xml File Convention (Next.js docs) —
app/sitemap.ts,generateSitemaps(), dan localized/image sitemaps. - umum SEO Issues pada Next.js situs web (Salt Agency) — sebuah 50-situs audit study dengan nyata data pada soft 404s dan LCP failures.
- How Google Handles JavaScript Throughout pengindeksan Process (Vercel) — render-timing data dari nextjs.org’s own server beacons.
- Complete Next.js SEO Guide (Strapi) — sebuah thorough framework-walkthrough covering rendering modes, metadata, dan data terstruktur.
- App Router vs halaman Router untuk SEO (Wisp) — sebuah focused comparison dari two routers dari sebuah SEO angle.
- r/TechSEO — community untuk rendering/pengindeksan debugging.
Stats worth citing
- Render timing adalah biasanya fast, occasionally very slow. Vercel’s analysis dari 37 000+ server-beacon pairs pada nextjs.org ditemukan sebuah median render time dari ~10 seconds, tetapi sebuah 90th percentile dari ~3 hours dan sebuah 99th percentile dari ~18 hours — which adalah exactly why Anda tidak ingin primary konten waiting pada render queue. Source
- CWV dan soft 404s adalah widespread pada nyata Next.js situs. Salt Agency’s audit dari 50
Next.js situs ditemukan 41/50 returning soft 404s (404 views di sebuah
200status) dan hanya 3/50 passing LCP thresholds — sebuah reminder itu framework’s CWV advantages hanya help jika Anda gunakannext/imagedenganprioritydan kembalikan nyata kode status. Source
Log perubahan
Diperbarui 18 Jul 2026.
Ringkasan editorial dan detail perubahan yang tercatat.Detail perubahan
-
Catatan perubahan terperinci saat ini tersedia dalam bahasa Inggris.
-
Catatan perubahan terperinci saat ini tersedia dalam bahasa Inggris.
-
Catatan perubahan terperinci saat ini tersedia dalam bahasa Inggris.
-
Catatan perubahan terperinci saat ini tersedia dalam bahasa Inggris.
Perbandingan lengkap tidak tersedia — tidak ada cuplikan sebelumnya yang diarsipkan untuk revisi ini.