Next.js 15 App Router ve Server Components

Ders 4/5 25 dakika

Metadata API ile SEO Optimizasyonu

Next.js Metadata API ile title, description, Open Graph ve Twitter Card meta etiketleri. Dinamik sayfalar için generateMetadata.

Next.js\'de SEO

Next.js 15\'in Metadata API\'si, SSR sayesinde arama motorlarının görebileceği gerçek meta etiketler üretir. CSR uygulamalarındaki SEO sorunları yoktur.

Statik Metadata

// app/blog/page.tsx
import { Metadata } from "next";

export const metadata: Metadata = {
  title: "Blog | Ininia Teknoloji",
  description: "Yazılım, teknoloji ve dijital dönüşüm hakkında güncel yazılar.",
  keywords: ["next.js", "react", "typescript", "web geliştirme"],
  openGraph: {
    title: "Blog | Ininia Teknoloji",
    description: "Yazılım ve teknoloji yazıları",
    type: "website",
    locale: "tr_TR",
    images: [
      {
        url: "https://ininia.com/og-image.png",
        width: 1200,
        height: 630,
      },
    ],
  },
  twitter: {
    card: "summary_large_image",
    title: "Blog | Ininia Teknoloji",
    description: "Yazılım ve teknoloji yazıları",
  },
};

export default function Blog() {
  return <div>...</div>;
}

Dinamik Metadata (generateMetadata)

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

interface Props {
  params: Promise<{ slug: string }>;
}

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const { slug } = await params;
  const yazi = await yaziGetir(slug);

  if (!yazi) {
    return { title: "Yazı Bulunamadı" };
  }

  return {
    title: `${yazi.baslik} | Blog`,
    description: yazi.ozet,
    openGraph: {
      title: yazi.baslik,
      description: yazi.ozet,
      type: "article",
      publishedTime: yazi.yayinTarihi,
      images: [{ url: yazi.kapakGorseli }],
    },
    alternates: {
      canonical: `https://sitem.com/blog/${slug}`,
    },
  };
}

export default async function BlogYazisi({ params }: Props) {
  const { slug } = await params;
  const yazi = await yaziGetir(slug);
  return <article>...</article>;
}

Root Layout\'ta Varsayılan Metadata

// app/layout.tsx
export const metadata: Metadata = {
  metadataBase: new URL("https://sitem.com"),
  title: {
    default: "Sitem",
    template: "%s | Sitem", // Her sayfaya " | Sitem" eklenir
  },
  description: "Varsayılan açıklama",
  robots: {
    index: true,
    follow: true,
  },
};

Sitemap Oluşturma

// app/sitemap.ts
import { MetadataRoute } from "next";

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const yazilar = await tumYazilariGetir();

  return [
    { url: "https://sitem.com", lastModified: new Date() },
    { url: "https://sitem.com/hakkimizda", lastModified: new Date() },
    ...yazilar.map(yazi => ({
      url: `https://sitem.com/blog/${yazi.slug}`,
      lastModified: new Date(yazi.guncellenmeTarihi),
    })),
  ];
}

Önemli Noktalar

  • metadata export ile statik SEO meta etiketleri tanımlanır
  • generateMetadata ile dinamik sayfalarda SEO verisi çekilir
  • Root layout'ta metadataBase ve template tanımlanmalı
  • app/sitemap.ts ile otomatik XML sitemap oluşturulur