Next.js SEO Rehberi

Next.js sitenizi taranabilir, dizine eklenebilir ve sıralanabilir hâle getirme rehberi; iki router'ı, SSG/SSR/ISR/Server Components oluşturma kiplerini, App Router Metadata API'sini, sitemap.ts'yi, robots.ts'yi, next/image'i, next/link'i ve sessizce sorun çıkaran hataları kapsar.

İlk yayın tarihi: 26 Haz 2026 · Son güncelleme: 8 Ağu 2026 · Advanced
Diller

Next.js, doğru kullanıldığında JavaScript SEO'sunun en zor sorunlarını büyük ölçüde çözer. App Router'ın Server Components varsayılanı ile SSG/ISR, içeriği oluşturma kuyruğunda bekletmeden HTML'ye koyar; yerleşik Metadata API, başlıkları, canonical'ları ve Open Graph verisini sunucuda çözer; sitemap.ts ile robots.ts dosya kurallarıdır. Framework altyapıyı sağlar ama etiketlerinizi sizin yerinize yazmaz. Eksik metadataBase, LCP görselinde priority bulunmaması, Client Component'ten export edilen metadata ve 200 dönen 404 görünümleri öngörülebilir hatalardır.

TL;DR — Next.js, doğru kullanıldığında en zor JavaScript SEO sorunlarını varsayılan olarak çözer. App Router varsayılan olarak Server Components kullanır ve SSG/SSR/ISR’yi destekler; bunların hepsi oluşturulmuş HTML gönderdiği için oluşturma kuyruğunda bekleme olmaz. Metadata’yı yerleşik Metadata API (metadata / generateMetadata) ile ayarlayın; metadataBase yoksa canonical ve OG görselleriniz göreli URL’lere dönüşür. app/sitemap.ts ile app/robots.ts dosya kurallarını kullanın, dinamik rotaları generateStaticParams ile önceden oluşturun, LCP görselinde priority ayarlayın ve bağlantıları gerçek next/link çapaları olarak bırakın. Pages Router da next/head üzerinden SEO’ya uygundur. Hatalar öngörülebilirdir; çoğu Next.js’in değil sizin yapılandırmanızın sonucudur.

Next.js burada nereye oturur?

Next.js is a React framework, so everything in JavaScript SEO applies. What makes it worth its own guide is that Next.js ships first-class answers to most JS-SEO problems: server rendering, static generation, a metadata system, and sitemap/robots conventions. The hard part isn’t whether Google can read it — Google has rendered JavaScript for years — it’s choosing the right rendering mode and not leaving the SEO basics unwired. This is a specialized case of headless CMS SEO: the CMS barely matters, the frontend’s rendering decisions decide everything.

Şu çerçeveyi akılda tutun: “Bu bir Next.js sitesi” demek, tek bir URL’nin nasıl sunulduğunu açıklamaz. Oluşturma kipi, önbellekleme ve Server/Client Component sınırları rota başına (bazen segment başına) belirlenir — aynı proje statik bir pazarlama sayfasını, SSR ürün sayfasını ve Client Component kullanan bir dashboard’u birlikte barındırabilir. Bir rotanın davranışını “uygulamanın tamamına” genellemeyin; belirli URL’yi test edin. “this is a Next.js site” (Türkçe çeviri) Cümle, ilgili HTTP davranışının sınırlarını pratik bir dille özetliyor.

İki router, iki farklı çalışma biçimi

Next.js’in iki router’ı vardır ve SEO’yu farklı şekilde ele alırlar:

  • Pages Router (eski model) — veri alma getStaticProps / getServerSideProps ile yapılır; metadata <Head> içindeki next/head ile (veya next-seo paketiyle) ayarlanır; Server Components yoktur.
  • App Router (v13+, güncel ve önerilen yaklaşım) — varsayılan olarak React Server Components; yerleşik Metadata API (metadata export / generateMetadata); app/sitemap.ts ve app/robots.ts dosya kuralları; dinamik rotalar için generateStaticParams. 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

İkisi de iyi sıralanabilir. App Router daha temiz ve bütünleşik bir metadata sistemi (yani next/head ile uğraşma ihtiyacı yok) ve hazır Server Components sunar; yeni bir projede ilk tercihim bu yüzden olur. Ancak “SEO için App Router zorunludur” bir efsanedir — Pages Router kullanan pek çok site iyi sıralanıyor. “App Router or you can’t do SEO” (Türkçe çeviri) Bu ifade, arama motoru davranışının ilgili sınırını netleştirir.

Oluşturma kipleri ve SEO açısından anlamları

How Google handles JavaScript is a three-phase pipeline — crawl, then a deferred render wave, then index. “All pages with a 200 HTTP status code are sent to the rendering queue.” The whole game in Next.js is choosing a mode that puts your content in the HTML before that render wave, so there’s nothing to wait for. 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 Site Generation (SSG) — sayfalar derleme zamanında önceden oluşturulur. HTML hemen hazırdır ve oluşturma kuyruğu riski yoktur. Her dakika değişmeyen içerik için idealdir. Hangi dinamik rotaların önceden oluşturulacağını App Router’da generateStaticParams(), Pages Router’da getStaticPaths() belirler.
  • Incremental Static Regeneration (ISR) — statik sayfalar belirli bir aralık sonunda yeniden doğrulanır (export const revalidate = 3600). Crawler’lar düşük TTFB ile statik HTML alır, içerik de güncel kalır. Güçlü bir varsayılandır; ancak bir tuzak vardır: pencere dolduktan sonraki ilk istek (Googlebot olabilir) yine eski sayfayı alır; güncel sürüm bir sonraki istekte sunulur. Gerçekten çok değişken verilerde (fiyat, stok) SSR daha güvenlidir.
  • Server-Side Rendering (SSR) — HTML istek başına oluşturulur. Tarayıcılar hemen tamamlanmış HTML alır; karşılığında sunucu gecikmesini izlemek gerekir; TTFB ve LCP’ye dikkat edin. export const dynamic = 'force-dynamic' veya istek zamanında kullanılan API’ler (cookies, headers) rotayı SSR’ye geçirir.
  • React Server Components (App Router varsayılanı) — sunucuda oluşturulur ve HTML gönderilir; bileşenin kendisi için JavaScript gönderilmez. İçerik ilk yanıtta bulunur, hydration boşluğu yoktur. SEO için en iyi varsayılandır. Etkileşim, 'use client' ile işaretlenen Client Components içindedir.
  • Client-Side Rendering (CSR) — tamamen tarayıcıda oluşturulur. Googlebot oluşturma dalgasından sonra dizine ekleyebilir (ortanca süre ~10 saniyedir, ancak 90. yüzdelik dilim saatlere uzar); diğer tarayıcılar — Bingbot, AI botları, sosyal önizleme botları — boş bir sayfa görebilir. App Router’da CSR isteğe bağlıdır ('use client'); Pages Router’da birincil içeriği useEffect içinde almayın. Sıralanmasını istediğiniz içerikte CSR kullanmayın.

Kendime sıklıkla hatırlattığım nokta şu: “Googlebot bunu oluşturabilir” demek, “Googlebot’un oluşturmasını istemelisiniz” demek değildir. Oluşturma pahalıdır, ertelenir ve bütün tarayıcılar için geçerli değildir. “Googlebot can render it” (Türkçe çeviri) Bu cümle, uygulamadaki kararın dayandığı normatif noktayı açıklıyor. “you should make Googlebot render it.” (Türkçe çeviri) Alıntı, yanıtın kapsamını ve beklenen istemci davranışını birlikte gösteriyor.

Metadata API (App Router)

Metadata API yalnızca Server Component’lerde çalışır — metadata, sayfa oluşturulmadan önce sunucuda çözülür ve ilk HTML’nin içine girer. metadata veya layout.js içinden page.js export edin:

export const metadata: Metadata = {
  title: 'My Page',
  description: 'Page description',
}

Etiketler alınan verilere bağlıysa generateMetadata() kullanın:

export async function generateMetadata({ params }) {
  const post = await getPost(params.slug)
  return { title: post.title, description: post.description }
}

SEO için önemli alanlar:

  • title — bir dizeyi, şablonu ('%s | Brand'), varsayılanı ve mutlak geçersiz kılmayı destekler. Şablonu kök layout’ta bir kez ayarlayın; sayfa başlıkları onu devralır.
  • description, alternates.canonical (App Router’da canonical ayarlamanın doğru yolu), openGraph (görseller mutlak URL’lere çözülmelidir), twitter (LinkedIn ve Slack önizlemelerinde de kullanılır) ve robots (index/follow ile max-snippet, max-image-preview gibi googleBot’e özel yönergeler).
  • metadataBase — canonical ve OG görsel URL’lerinin doğru çözülmesi için zorunludur. Bunu unutmak Next.js metadata’sındaki en yaygın hatadır: göreli URL’ler canonical ve Open Graph etiketlerine sızar, sosyal önizlemeleri bozar ve canonical sinyallerini bulanıklaştırır.

Başlık şablonu örneği:

// 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>

İki tuzak. Birincisi, metadata layout’tan sayfaya sığ olarak birleştirilir — alt segmentte tanımlanan openGraph gibi iç içe bir nesne, üst nesnenin tamamının yerini alır. Bu nedenle sayfa seviyesindeki openGraph: { title: 'Home' }, layout’ta tanımlanmış openGraph.images değerini sessizce atabilir. İkincisi — insanların gözden kaçırdığı nokta — metadata yalnızca Server Components’te çalışır. 'use client' dosyasından export ederseniz hiçbir şey olmaz.

Akış metadata’sı. Dinamik oluşturulan sayfalarda generateMetadata, ilk HTML’den sonra metadata’yı akışla gönderebilir. Googlebot JavaScript çalıştırıp tam DOM’u incelediği için akış metadata’sı Google için çalışır. Ancak Next.js “HTML ile sınırlı botları” — Bingbot, Twitterbot, Slackbot, facebookexternalhit — algılar ve bunlara bunun yerine <head> içinde engelleyici metadata gönderir. Next.js belgelerinin ifadesiyle: “streaming metadata is disabled for bots and crawlers that expect metadata to be in the <head> tag.” (çeviri) “Akış metadata’sı, metadata’nın <head> etiketinde olmasını bekleyen botlar ve crawler’lar için devre dışıdır.” Bu otomatik gerçekleşir; yapılandırma gerekmez. Çoğu rakip rehberin değinmediği bu ayrıntı, akışı bekleyemeyen botlar için neden risk olmadığını açıklar. Önceden oluşturulan sayfalar tamamen farklıdır: metadata derleme zamanında çözüldüğü için akış yoktur. Bu davranış sürüme özeldir (Next.js 16.2.10 itibarıyla güncel); yükseltme yaptığınızda generateMetadata belgelerini yeniden kontrol edin. Ayrıca sunum yolları giriş noktasına göre değiştiğinden metadata’yı tek değil iki şekilde doğrulayın: doğrudan/üretim isteği (curl -I veya View Source) ve aynı rotaya istemci tarafı geçiş — <head> bu iki durumda farklı güncellenebilir.

Evidence for this claim Prerendered Next.js pages do not use streaming metadata because metadata is resolved at build time in the documented path. Scope: route output, metadata and deployment Confidence: high · Verified: Metadata and OG images

next/head ile metadata (Pages Router)

Pages Router’da metadata, <Head> içindeki next/head bileşeninde bulunur:

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 */}
    </>
  )
}

Başlık ve açıklamayı yalnızca _app.js’te değil, her sayfa için ayarlayın; sayfalandırılmış varyantlar da dahil olmak üzere her sayfaya canonical koyun. next-seo paketi bunu <NextSeo> bileşeni ve yapılandırılmış veri yardımcılarıyla standartlaştırır. App Router’a geçiş çoğunlukla next/head ve next-seo yerine yerleşik metadata export’unu kullanmak demektir.

next-seo paketine ihtiyacınız var mı? Bu paket Next.js’in parçası olmayan, üçüncü taraf bir eklentidir; metin yazıldığı sırada v7,2,0 numaralı sürümde, etkin biçimde bakımı yapılmakta ve arşivlenmiş değildir. Kendi belgeleri rolünü açıkça anlatır: App Router’da standart meta etiketleri için README, generateMetadata yerine Next.js’in yerleşik metadata/<NextSeo> export’unu önerir; Pages Router’da ise <NextSeo>, next/head üzerinde makul bir kolaylık katmanıdır. Paketin App Router’da hâlâ sunduğu kullanım, bazı ekiplerin ArticleJsonLd etiketini elle yazmaya tercih ettiği JSON-LD yardımcı bileşenleridir (FAQPageJsonLd ile useAppDir, <script type="application/ld+json"> vb.). Sonuç: yeni bir App Router projesinde önce yerleşik Metadata API’ye yönelin; paket isteğe bağlıdır, zorunlu değildir ve bakımcıları da bunu söylüyor.

Sitemap’ler

App Router’da app/sitemap.ts, /sitemap.xml çıktısı üreten bir dosya kuralıdır:

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 },
  ]
}

Büyük sitelerde generateSitemaps() birden çok dosyaya böler (Google’ın sınırı sitemap başına 50 000 URL’dir); her dosya /.../sitemap/[id].xml altında sunulur. Sitemap çıktısı ayrıca görsel sitemap’lerini, video sitemap’lerini ve yerelleştirilmiş alternates.languages alanını destekler. Pages Router’da next-sitemap kullanın veya pages/sitemap.xml.js ile getServerSideProps üretin.

robots.txt

app/robots.ts, robots dosyanızı programlı olarak üretir:

export default function robots(): MetadataRoute.Robots {
  return {
    rules: [{ userAgent: '*', allow: '/', disallow: '/private/' }],
    sitemap: 'https://acme.com/sitemap.xml',
  }
}

Kullanıcı aracısına özel kurallar ve birden çok sitemap desteklenir. Pages Router statik bir public/robots.txt kullanır. Her iki router’da da yanılmamanız gereken kural şudur: JavaScript veya CSS’ye asla disallow uygulamayın — Google engellenen dosyalardan sayfayı oluşturamaz; JavaScript framework’ünde bu, sayfayı tamamen boş bırakabilir.

next/image ve Core Web Vitals

next/image, SEO için framework’ü seçmenin en güçlü nedenlerinden biridir. Ekranın altındaki görselleri gecikmeli yükler; alan ayırmak için width/height (veya fill) ister ve layout kaymasını / CLS’yi önler; WebP/AVIF’i otomatik sunar ve srcset prop’undan doğru bir sizes üretir. En önemli CWV ayarı, hero ya da ekranın üst kısmındaki görselde bulunan priority prop’udur; bu prop görseli önceden yükleyerek LCP’yi hızlandırır:

<Image src="/hero.jpg" width={1200} height={630} priority alt="Hero" />

LCP görselinde priority unutmak en yaygın Next.js CWV hatasıdır; gerçek Next.js sitelerinde CWV sorunları da yaygındır (Salt Agency verileri için Stats sekmesine bakın). alt zorunludur: dekoratif görsellerde boş bırakın, içerik görsellerinde açıklayıcı metin verin.

next/link, HTML içinde standart <a href> çapaları üretir; Google bunları normal şekilde izler. Ayrıca üretimde görünür alan içindeki bağlantılar için istemci tarafı geçiş ve arka planda önceden getirme özelliği sağlar. SEO kuralı basittir: iç bağlantılarda next/link kullanın; gerçek bir çapa üretmeyen onClick işleyicisi veya JavaScript yönlendirmesiyle asla değiştirmeyin — bu bağlantılar taranamaz. Gerekirse düşük değerli bağlantılarda bant genişliğinden tasarruf etmek için prefetch={false} kullanın.

Dinamik rotalar ve generateStaticParams

generateStaticParams(), Next.js’e hangi dinamik rotaların derleme zamanında önceden oluşturulacağını söyler:

// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = await getPosts()
  return posts.map((post) => ({ slug: post.slug }))
}

Bu şekilde oluşturulan sayfalar tamamen statik HTML’dir ve SEO için en iyisidir. Bu fonksiyon olmazsa dinamik rotalar varsayılan olarak isteğe göre (SSR) oluşturulur; bu da çalışır, ancak sunucu gecikmesini geri getirir. Düzenli güncellenen içerik için revalidate (ISR) ile birleştirin. Önemli tüm dinamik URL’lerin generateStaticParams içinde olduğundan emin olun; hiçbir şey oluşturma kuyruğunda beklemesin.

Yapılandırılmış veri (JSON-LD)

Metadata API’de yapılandırılmış veri alanı yoktur — JSON-LD’yi bir Server Component içindeki <script> olarak ekleyin; böylece istemci bundle’ına maliyet yüklemeden sunucu tarafından oluşturulan HTML’de kalır:

const jsonLd = { '@context': 'https://schema.org', '@type': 'Article', /* … */ }
return <script type="application/ld+json"
  dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />

Article/BlogPosting, BreadcrumbList, Product ve FAQPage en yaygın türlerdir. Her oluşturma değişikliğinden sonra Rich Results Test ile doğrulayın.

Yaygın Next.js SEO hataları

Gerçek denetimlerden ve yukarıdaki örüntülerden çıkanlar:

  1. Missing or relative canonicals — often from a forgotten metadataBase, which also breaks OG image URLs.
  2. No priority on the LCP image — the biggest CWV miss.
  3. 404 views returning 200 — use the built-in notFound() to return a real status; soft 404s are rampant on Next.js sites.
  4. metadata exported from a Client Component — silently does nothing; it’s Server Component only.
  5. CSR for primary content — fetching critical content in useEffect means non-Google crawlers get empty pages.
  6. Hash (#) routing instead of the History API — those views aren’t separately crawlable.
  7. Not exporting generateStaticParams — dynamic routes render on-demand instead of being pre-built.
  8. openGraph overwritten by layout inheritance — child segments replace, not merge.
  9. Blocking JS/CSS in robots.txt or via a Content Security Policy that stops Googlebot’s headless Chrome from loading scripts — test with URL Inspection.

Dağıtım notları

Next.js, Vercel tarafından geliştirilir; orada barındırmak (statik ve ISR sayfaları için edge CDN, iyi TTFB) sıkı bir entegrasyon sağlar ama zorunlu değildir. Tarayıcılara güvenilir sinyal vermek için kalıcı yönlendirmeleri redirects() içindeki next.config.js ile tanımlayın (308 veya permanent: true ile 301), güvenlik ve önbellek başlıklarını headers() üzerinden ayarlayın; sayfa başına X-Robots-Tag metadata’sı uygun olmadığında yol tabanlı noindex kuralları için robots yanıt başlıklarını kullanın.

Neyi nerede kontrol etmeli? Önbellek durumu, durum kodları, yönlendirmeler ve akış metadata’sı tek bir testte görünmez; bir rota bir kontrolde iyi görünüp başka birinde bozuk olabilir:

KontrolBakılacak yerOluşturulmuş görünümden neden farklı olabilir
Önbellek/yeniden doğrulama yaşıDoğrudan isteğin yanıt başlıkları (curl -I)ISR, pencere dolduktan hemen sonraki istekte eski sayfayı sunabilir
Doğrudan HTTP durumuOluşturulmuş arayüz değil, üretim URL’sinde curl -InotFound() çağrılmadan gösterilen “bulunamadı” görünümü yine 200 döndürür
Yönlendirme davranışıYönlendirmeyi tetikleyen gerçek bağlam — Server Action içindeki redirect(), Route Handler veya istemcide onClickDurum kodu ve yanıt yolu yalnızca hedefe değil çağrı bağlamına da bağlıdır
Akış metadata’sıAynı rotaya doğrudan istek ve istemci tarafı geçişSıradan istemciler akış metadata’sı alabilir; HTML ile sınırlı botlar engelleyici metadata alır; iki yol aynı değildir
İstemci tarafı geçişlerUygulama içinde geçiş yapın, sonra <head>’i yeniden kontrol edinİlk yüklemede doğru olan bir rota, istemci geçişinden sonra sapabilir

Bunların hiçbiri framework tarafından garanti edilmez — Next.js mekanizmaları (redirects(), notFound(), yeniden doğrulama, akış) sağlar; ancak önbellek anahtarları, geçersizleştirme, önizleme durumu ve dağıtım yapılandırması hâlâ sizin sorumluluğunuzdadır. Bunları yalnızca yerelde değil üretimde de test edin.

Son bir dinamik oluşturma notu — botlara önceden oluşturulmuş HTML, kullanıcılara JavaScript sunmak. Google bunu bir öneri olarak kullanımdan kaldırdı: “dynamic rendering was a workaround and not a long-term solution.” (çeviri) “Dinamik oluşturma bir geçici çözümdü ve uzun vadeli bir çözüm değildi.” Next.js’te buna zaten ihtiyacınız yok; SSR, SSG, ISR ve Server Components içeriği doğal olarak HTML’ye koyar. Bir denetimde karşınıza çıktığında tanıyabilmeniz için adını bilin, ancak bunun üzerine kurulum yapmayın.

İdeal yol: App Router + Server Components + ISR + Metadata API (metadataBase ile) + next/image ayarlı priority. Bunları doğru kurduğunuzda Next.js SEO’sunun büyük kısmı kendiliğinden hallolur.

Add an expert note

Pin an expert quote

New person? Create their unclaimed profile at /admin/experts/ → Pin a quote first.