10 / 12
Metadata ve SEO
metadata, generateMetadata, OG görseli, sitemap, robots ve JSON-LD.
SEO'da Next.js'in Payı
Google'ın başlangıç rehberine göre arama motorunun işi üç adımdır: sayfayı bulmak, taramak ve içeriği anlamak.1 Google JavaScript'i de çalıştırabilir ama bunu sonradan, ayrı bir sırada yapar; sunucuda render edilmiş HTML bu adımı kolaylaştırır.2 App Router sayfaları zaten sunucuda render eder ve botlara akış yerine tamamlanmış HTML gönderir.3
Geriye sizin işiniz kalır: her sayfaya doğru başlık ve açıklama, paylaşım görseli, site haritası ve gerekiyorsa yapılandırılmış veri.
Statik metadata
layout.tsx ya da page.tsx'ten bir metadata nesnesi export edin. Next.js <head> etiketlerini kendisi üretir. Yalnızca Server Component'lerde çalışır.4
// app/layout.tsx
import type { Metadata } from "next";
export const metadata: Metadata = {
metadataBase: new URL("https://shop.example.com"),
title: { default: "Mağaza", template: "%s | Mağaza" },
description: "Next.js ile kurulmuş küçük bir ürün kataloğu.",
};// app/products/page.tsx
export const metadata: Metadata = { title: "Ürünler" }; // → "Ürünler | Mağaza"title.templatealt segmentlerdeki başlığa ek yapar. Template kullanıyorsanızdefaultzorunludur.5metadataBasesayesinde OG görseli ve canonical gibi alanlara göreli adres yazabilirsiniz.5
Veriye Bağlı metadata
Ürün sayfasının başlığı üründen gelir. generateMetadata bunun için:4
// app/products/[slug]/page.tsx
export async function generateMetadata({
params,
}: PageProps<"/products/[slug]">): Promise<Metadata> {
const { slug } = await params;
const product = await getProduct(slug);
if (!product) return {};
return {
title: product.name,
description: product.description,
alternates: { canonical: `/products/${product.slug}` },
};
}Sayfa ve generateMetadata aynı veriyi okuyor. getProduct "use cache" ile ya da React.cache ile sarılıysa sorgu bir kez çalışır.4
Dinamik sayfalarda Next.js metadata'yı akıtır: görsel içerik önce gelir, <head> etiketleri hazır olunca eklenir. <head>'de görmeyi bekleyen botlar (Twitterbot, Slackbot, Bingbot gibi) user agent'larından tanınır ve tamamlanmış sayfayı alır.4
Paylaşım Görseli, Sitemap ve robots
Bazı metadata dosya adıyla tanımlanır. Dosyayı ilgili klasöre koymanız yeter:6
| Dosya | Sonuç |
|---|---|
app/favicon.ico, app/icon.png | Site ikonu |
app/opengraph-image.png | Varsayılan paylaşım görseli |
app/products/[slug]/opengraph-image.tsx | Her ürün için kodla üretilen görsel |
app/sitemap.ts | /sitemap.xml |
app/robots.ts | /robots.txt |
// app/sitemap.ts
import type { MetadataRoute } from "next";
import { getProducts } from "@/lib/products";
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const products = await getProducts();
return [
{ url: "https://shop.example.com/products" },
...products.map((product) => ({
url: `https://shop.example.com/products/${product.slug}`,
})),
];
}// app/robots.ts
import type { MetadataRoute } from "next";
export default function robots(): MetadataRoute.Robots {
return {
rules: { userAgent: "*", allow: "/", disallow: "/cart" },
sitemap: "https://shop.example.com/sitemap.xml",
};
}Paylaşım görselini kodla üretmek için next/og'daki ImageResponse JSX ve CSS'ten PNG oluşturur. Yalnızca flexbox ve CSS'in bir alt kümesi desteklenir; display: grid çalışmaz.4
// app/products/[slug]/opengraph-image.tsx
import { ImageResponse } from "next/og";
import { getProduct } from "@/lib/products";
export const size = { width: 1200, height: 630 };
export const contentType = "image/png";
export default async function Image({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
const product = await getProduct(slug);
return new ImageResponse(
<div style={{ display: "flex", width: "100%", height: "100%", alignItems: "center", justifyContent: "center", fontSize: 96, background: "white" }}>
{product?.name ?? "Mağaza"}
</div>,
size,
);
}Yapılandırılmış Veri: JSON-LD
JSON-LD, sayfanın bir ürün, makale ya da etkinlik olduğunu makinenin anlayacağı şekilde anlatır. Google bunu zengin sonuçlar (fiyat, puan) için kullanır.7 Next.js'in önerisi sayfada bir <script type="application/ld+json"> render etmektir:8
const jsonLd = {
"@context": "https://schema.org",
"@type": "Product",
name: product.name,
description: product.description,
offers: { "@type": "Offer", price: product.price, priceCurrency: "TRY" },
};
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd).replace(/</g, "\\u003c") }}
/>;Hata
JSON.stringify HTML'i temizlemez. Ürün adında </script> gibi bir değer XSS açığı yaratabilir. Örnekteki < → < değişimini atlamayın.8
Sonucu Google'ın Rich Results Test aracıyla kontrol edin.8 Sayfa hızı da sıralamayı etkiler; Core Web Vitals, görsel ve font Performans ve Erişilebilirlik rehberinde.
Kendin Dene
Ürün sayfasını açıp DevTools'ta
<head>'e bakın.<title>template'e göre mi oluşmuş?/sitemap.xmlve/robots.txtadreslerini açın.opengraph-image.tsx'i ekleyin ve/products/canvas-sneaker/opengraph-imageadresinde görseli görün.Ürün adını
<b>Test</b>yapıp JSON-LD'yireplaceolmadan ve onunla render edin; sayfa kaynağını karşılaştırın.
Detaylı Öğrenmek İçin
Resmi doküman: Google Search Central "SEO Starter Guide"; bir sitenin aramada nasıl bulunduğunu temelden anlatır.1
Resmi doküman: Google'ın "JavaScript SEO basics" sayfası; Googlebot'un JavaScript'i nasıl işlediği ve sunucuda render'ın yeri.2
Resmi doküman: Next.js
generateMetadatareferansı; tüm metadata alanları ve Cache Components ile davranışı.5
Kaynaklar
Arama motorunun sayfayı bulması, taraması ve anlaması için temel uygulamalar.
Googlebot'un tarama, render ve dizine ekleme aşamaları.
Botlara tamamlanmış HTML gönderilmesi.
Statik ve üretilen metadata, akış, veri tekrarını önleme, dosya tabanlı metadata ve `ImageResponse`.
Metadata alanları, `title.template`, `metadataBase` ve `alternates`.
`icon`, `opengraph-image`, `sitemap` ve `robots` dosya kuralları.
Yapılandırılmış verinin ne işe yaradığı ve JSON-LD önerisi.
`<script>` ile JSON-LD, XSS'e karşı `<` kaçışı ve doğrulama araçları.
Son güncelleme tarihi: 21 Ekim 2026
