Tüm Yazılara Dön
React & Next.js
1 Eylül 2026
10 dk okuma

Next.js App Router'da Canonical Nasıl Eklenir?

Intent
Next.js SEO

Next.js App Router'da canonical, Metadata API içindeki alternates.canonical alanıyla üretilir. Intent'in kullandığı sürüm next@16.2.10; bu sürümde dinamik route parametreleri Promise olarak alınabilir. Canonical'ı root layout'ta tek bir sabit değer yapmak, alt sayfaları yanlışlıkla ana sayfaya canonicalize edebilir.

Statik sayfa

import type { Metadata } from "next";

export const metadata: Metadata = {
  title: "Teknik SEO Rehberi | Intent",
  description: "Teknik SEO sorunlarını teşhis etmek için uygulama rehberi.",
  alternates: {
    canonical: "/hub/rehberler/teknik-seo",
  },
};

Next.js Metadata API dokümanı statik metadata nesnesi ile dinamik generateMetadata fonksiyonunun ayrı kullanım amaçlarını gösterir. Statik sayfa için sabit relative canonical yeterlidir.

Intent'teki dinamik blog route'u

Bu repository'deki gerçek route src/app/blog/[slug]/page.tsx içinde generateMetadata kullanır. Aynı veri kaynağıyla sadeleştirilmiş karşılığı:

import type { Metadata } from "next";
import { getPostBySlug } from "@/lib/blog";

export async function generateMetadata(
  { params }: { params: Promise<{ slug: string }> }
): Promise<Metadata> {
  const { slug } = await params;
  const post = getPostBySlug(slug);

  return {
    title: `${post.title} | Intent Blog`,
    description: post.description,
    alternates: {
      canonical: `/blog/${post.slug}`,
    },
  };
}

Buradaki post.slug, ham query veya eski slug değil, içerik kaynağındaki normalize edilmiş değerdir. Veri bulunmuyorsa route 404 döndürmelidir; olmayan bir kaynağa canonical üretmek yerine notFound() kullanmak daha temizdir.

metadataBase ve host edge case'leri

Intent'in root layout'ında:

export const metadata: Metadata = {
  metadataBase: new URL("https://intent.com.tr"),
};

Bu sayede canonical: "/blog/ornek" değeri production HTML'sinde https://intent.com.tr/blog/ornek olur. Relative URL'lerin metadataBase ile birleştirilmesi Next.js dokümantasyonunda açıklanır.

DurumRiskKontrol
localhost:3000Test host'unun canonical'a sızmasıBuild HTML'sinde localhost ara
Vercel previewPreview URL'nin production yerine çıkmasıPreview response head'ini incele
www / non-wwwAynı içeriğin iki hostta üretilmesiRedirect ve canonical politikasını eşleştir
HTTP / HTTPSGüvenli olmayan adresin sinyal olmasıHTTPS canonical bekle
?utm_source=...Analytics parametresinin canonical'a taşınmasıCanonical path'in query içermediğini doğrula
trailing slashİki path biçiminin ayrışmasıTek slash politikasını kullan

Altı katmanlı metadata verification

“View source'ta gördüm” tek başına yeterli değildir:

  1. Source: Route metadata veya generateMetadata hangi değeri döndürüyor?
  2. Build: next build metadata üretirken hata veriyor mu?
  3. HTTP: Gerçek host hangi status, redirect ve header'ları döndürüyor?
  4. Server HTML: curl ile gelen HTML içinde canonical var mı?
  5. DevTools: Elements DOM'u client script sonrasında değişiyor mu?
  6. Search Console: URL Inspection Google-selected canonical için ne gösteriyor?
curl -sS -D - https://intent.com.tr/blog/ornek-yazi -o /tmp/intent-page.html
rg -oi '<link[^>]+rel="canonical"[^>]*>' /tmp/intent-page.html
rg -oi 'https?://[^" ]*localhost[^" ]*|https?://[^" ]*vercel.app[^" ]*' /tmp/intent-page.html

DOM inspection tarayıcının mevcut DOM'unu, curl ise sunucunun döndürdüğü ilk HTML'yi gösterir. Client-side canonical mutasyonuna güvenmeyin.

Repository regression kontrolü

PAGE="https://intent.com.tr/blog/google-selected-canonical-neden-farkli"
HTML="$(curl -fsSL "$PAGE")"
grep -qi 'rel="canonical"' <<< "$HTML"
grep -q 'https://intent.com.tr/blog/google-selected-canonical-neden-farkli' <<< "$HTML"
test "$(grep -o '<h1\b' <<< "$HTML" | wc -l)" -eq 1

Sonra sitemap loc değerini ve makale iç linklerini aynı path ile karşılaştırın. Bu kontrol canonical'ın doğru yazıldığını kanıtlar; Google'ın mutlaka onu seçeceğini kanıtlamaz.

Sık hatalar

  • Root layout'a canonical: "/" koyup bütün alt route'ları ezmek.
  • post.slug yerine ham query veya eski slug kullanmak.
  • Sitemap'te query parametreli URL bulundurmak.
  • Preview host'unu production metadataBase yerine geçirmek.
  • Canonical değişikliğini içerik kopyasını çözmeden kullanmak.

Canonical doğru üretildiğinde URL tercih sinyali netleşir. İndeksleme için yine 200 yanıt, erişilebilir HTML, anlamlı iç bağlantılar ve bağımsız içerik gerekir. Sinyaller için Google-selected canonical teşhis matrisine bakın.