aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Web Geliştirme

Next.js SEO: Metadata API ile Başlık, OG ve Canonical

Next.js SEO denince akla ilk gelen, sayfanın <head> bölümünü doğru doldurmaktır: anlamlı bir başlık, açıklayıcı bir açıklama, sosyal paylaşım için Open Graph etiketleri ve tekrar eden içerikleri engelleyen canonical bağlantısı. App Router ile gelen Metadata API bu işi elle <head> yazmadan, tip güvenli ve sunucu tarafında çözülen bir şekilde yapmanı sağlar. Bu yazıda statik metadata nesnesinden dinamik generateMetadata fonksiyonuna kadar pratik bir kurulum anlatıyorum.

Metadata API nedir?

App Router'da (Next.js 13.2 ve sonrası) her layout.tsx ve page.tsx dosyası iki yoldan biriyle metadata dışa aktarabilir: sabit değerler için bir metadata nesnesi, isteğe veya veriye bağlı değerler için ise asenkron bir generateMetadata fonksiyonu. Next.js bunları okuyup sayfanın <head> bölümünü senin için üretir. Önemli kural: bu dışa aktarmalar yalnızca Server Component dosyalarında çalışır; başına "use client" yazılmış bir dosyadan metadata export edemezsin.

Statik metadata ile başlık ve açıklama

En basit hâli, sabit bir nesne dışa aktarmaktır. Genelde bunu kök app/layout.tsx içine site geneli için, sonra her sayfaya özel olarak ekarsın.

// app/layout.tsx
import type { Metadata } from "next";

export const metadata: Metadata = {
  title: {
    default: "aslain.dev — Web & Oyun Geliştirme",
    template: "%s | aslain.dev",
  },
  description: "Web, oyun sunucusu ve Discord bot geliştirme üzerine rehberler.",
};

title.template alanı güçlü bir araçtır: alt sayfalar sadece kendi başlığını verir, Next.js de %s yerine onu koyup sonuna site adını ekler. Örneğin bir sayfada title: "İletişim" dersen çıktı İletişim | aslain.dev olur. Marka adını her başlıkta elle tekrarlamaktan kurtulursun.

generateMetadata ile dinamik Next.js SEO

Blog yazısı, ürün sayfası gibi içeriği veritabanından gelen rotalarda başlık ve açıklama da dinamik olmalı. Burada generateMetadata devreye girer. Aynı params argümanını sayfanın kendisi gibi alır, veriyi çeker ve metadata döndürür.

// app/blog/[slug]/page.tsx
import type { Metadata } from "next";

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

  return {
    title: post.title,
    description: post.excerpt,
  };
}

Next.js 15 ile params bir Promise hâline geldi, bu yüzden await ile çözmen gerekir. Önemli bir performans notu: generateMetadata içinde yaptığın fetch çağrıları, aynı sayfa bileşeninde tekrar edildiğinde Next.js'in istek tekilleştirmesi (request memoization) sayesinde tek seferde çalışır; aynı veriyi iki kez çekmekten korkma.

Open Graph ve Twitter kartları

Bağlantın WhatsApp, X veya LinkedIn'de paylaşıldığında nasıl göründüğünü Open Graph etiketleri belirler. Metadata API bunları openGraph ve twitter anahtarları altında düzgün biçimde sunar.

export const metadata: Metadata = {
  openGraph: {
    title: "Next.js SEO Rehberi",
    description: "Metadata API ile başlık, OG ve canonical.",
    url: "https://aslain.dev/blog/nextjs-seo",
    siteName: "aslain.dev",
    images: [{ url: "/og/nextjs-seo.png", width: 1200, height: 630 }],
    locale: "tr_TR",
    type: "article",
  },
  twitter: {
    card: "summary_large_image",
    title: "Next.js SEO Rehberi",
    images: ["/og/nextjs-seo.png"],
  },
};
  • Görsel boyutu: 1200×630 piksel sosyal platformların beklediği standart orandır.
  • type: "article": blog yazıları için doğru OG tipi; ana sayfa için "website" kullan.
  • Twitter kartını ayrı belirtmezsen, çoğu alan Open Graph'tan miras alınır; yine de card tipini açıkça vermek iyi olur.

Canonical ve dil alternatifleri

Aynı içeriğe birden fazla URL'den ulaşılıyorsa (örneğin sondaki eğik çizgi, takip parametreleri), arama motorlarına asıl adresi söylemek için canonical etiketi şarttır. Metadata API bunu alternates altında verir.

export const metadata: Metadata = {
  metadataBase: new URL("https://aslain.dev"),
  alternates: {
    canonical: "/blog/nextjs-seo",
    languages: {
      "tr-TR": "/tr/blog/nextjs-seo",
      "en-US": "/en/blog/nextjs-seo",
    },
  },
};

metadataBase alanını mutlaka tanımla: göreli yollar (/blog/... veya /og/... gibi) bu temel adrese göre tam URL'ye çevrilir. Tanımlamazsan Next.js geliştirme aşamasında uyarı verir ve OG görselleri mutlak URL olmadığı için bazı platformlarda görünmeyebilir. languages altında verdiğin alternatifler ise hreflang etiketlerine dönüşerek çok dilli SEO'yu güçlendirir.

Sık yapılan hatalar

  • Client bileşeninden export: "use client" olan bir dosyadan metadata vermek sessizce işe yaramaz; metadata'yı bir Server Component'te tut.
  • metadataBase'i unutmak: OG görselleri ve canonical göreli kaldığı için bozulur.
  • Başlığı iki kez tanımlamak: hem title hem openGraph.title farklı olabilir; tutarlı tutmazsan paylaşımda kafa karışır.
  • Manuel <head> ile karıştırmak: App Router'da <head> elemanını elle yazma, Metadata API tek kaynak olmalı.

Sık Sorulan Sorular

metadata nesnesi mi yoksa generateMetadata mı kullanmalıyım?

Değerler sabitse (statik sayfalar, kök layout) metadata nesnesi daha basit ve hızlıdır. Başlık ya da açıklama veriden, parametreden veya istekten geliyorsa generateMetadata kullan. İkisini aynı dosyada birlikte export etme; Next.js buna izin vermez.

Sitemap ve robots dosyalarını da Metadata API mi üretir?

Evet. app/sitemap.ts ve app/robots.ts dosyaları, dosya tabanlı metadata kuralları kapsamındadır ve Next.js bunları otomatik olarak /sitemap.xml ile /robots.txt uçlarına çevirir. Aynı şekilde app/icon.png ve app/opengraph-image.tsx de tanınır.

generateMetadata sayfa yüklenmesini yavaşlatır mı?

Genelde hayır. İçindeki veri çağrıları sayfa bileşeniyle aynı önbelleğe takılır (request memoization), yani aynı fetch iki kez ağ isteği yapmaz. Yine de gereksiz ağır sorgulardan kaçın ve mümkünse önbelleklenebilir veri kaynakları kullan.

Sitenin Next.js SEO altyapısını baştan kurmak veya mevcut metadata'nı denetlemek mi istiyorsun? App Router, Open Graph ve canonical yapısını projene göre kuralım — benimle iletişime geç.

Bu kategorideki tüm yazılar →

Devamı için