İçeriğe geç
SEO

Next.js SEO Checklist: Proje Başlangıç Kontrol Listesi

Tarık Tunç
Next.js SEO Checklist: Proje Başlangıç Kontrol Listesi

Next.js SEO Checklist: Proje Başlangıç Kontrol Listesi

Next.js, SEO dostu web uygulamaları geliştirmek için mükemmel bir framework'tür. Sunucu tarafı rendering, statik site oluşturma ve dahili optimizasyon araçları sayesinde arama motorlarında üst sıralara çıkmanızı kolaylaştırır. Bu rehberde yeni bir Next.js projesi başlatırken uygulamanız gereken SEO kontrol listesini adım adım ele alacağız.

1. Metadata ve Head Yapılandırması

App Router ile Metadata

// app/layout.js — Global metadata
export const metadata = {
  metadataBase: new URL('https://www.example.com'),
  title: {
    default: 'Site Adı — Ana Açıklama',
    template: '%s | Site Adı',
  },
  description: 'Sitenizin genel açıklaması. 150-160 karakter ideal.',
  keywords: ['anahtar kelime 1', 'anahtar kelime 2'],
  authors: [{ name: 'Yazar Adı' }],
  creator: 'Yazar Adı',
  publisher: 'Site Adı',
  robots: {
    index: true,
    follow: true,
    googleBot: {
      index: true,
      follow: true,
      'max-video-preview': -1,
      'max-image-preview': 'large',
      'max-snippet': -1,
    },
  },
  openGraph: {
    type: 'website',
    locale: 'tr_TR',
    url: 'https://www.example.com',
    siteName: 'Site Adı',
    title: 'Site Adı — Ana Açıklama',
    description: 'Open Graph açıklaması',
    images: [
      {
        url: '/og-default.jpg',
        width: 1200,
        height: 630,
        alt: 'Site Adı',
      },
    ],
  },
  twitter: {
    card: 'summary_large_image',
    site: '@twitterHandle',
    creator: '@twitterHandle',
  },
  alternates: {
    canonical: 'https://www.example.com',
    languages: {
      'tr-TR': 'https://www.example.com',
      'en-US': 'https://en.example.com',
    },
  },
  verification: {
    google: 'google-verification-code',
    yandex: 'yandex-verification-code',
  },
};

Sayfa Bazlı Metadata

// app/blog/[slug]/page.js
export async function generateMetadata({ params }) {
  const post = await getPost(params.slug);

  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      type: 'article',
      publishedTime: post.publishedAt,
      modifiedTime: post.updatedAt,
      authors: [post.author.name],
      images: [{ url: post.coverImage, width: 1200, height: 630 }],
    },
    alternates: {
      canonical: `/blog/${params.slug}`,
    },
  };
}

2. Sitemap ve Robots.txt

// app/sitemap.js — Dinamik sitemap
export default async function sitemap() {
  const posts = await getAllPosts();
  const pages = await getAllPages();

  const postUrls = posts.map(post => ({
    url: `https://www.example.com/blog/${post.slug}`,
    lastModified: new Date(post.updatedAt),
    changeFrequency: 'weekly',
    priority: 0.8,
  }));

  const pageUrls = pages.map(page => ({
    url: `https://www.example.com/${page.slug}`,
    lastModified: new Date(page.updatedAt),
    changeFrequency: 'monthly',
    priority: 0.6,
  }));

  return [
    {
      url: 'https://www.example.com',
      lastModified: new Date(),
      changeFrequency: 'daily',
      priority: 1.0,
    },
    ...postUrls,
    ...pageUrls,
  ];
}
// app/robots.js — Dinamik robots.txt
export default function robots() {
  return {
    rules: [
      {
        userAgent: '*',
        allow: '/',
        disallow: ['/api/', '/admin/', '/private/'],
      },
    ],
    sitemap: 'https://www.example.com/sitemap.xml',
  };
}

3. Structured Data (JSON-LD)

// components/JsonLd.js
export default function JsonLd({ data }) {
  return (
    <script
      type="application/ld+json"
      dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}
    />
  );
}

// app/page.js — Organization schema
import JsonLd from '@/components/JsonLd';

export default function Home() {
  const organizationSchema = {
    '@context': 'https://schema.org',
    '@type': 'Organization',
    name: 'Site Adı',
    url: 'https://www.example.com',
    logo: 'https://www.example.com/logo.png',
    sameAs: [
      'https://twitter.com/handle',
      'https://github.com/handle',
      'https://linkedin.com/in/handle',
    ],
  };

  return (
    <>
      <JsonLd data={organizationSchema} />
      {/* Sayfa içeriği */}
    </>
  );
}

// app/blog/[slug]/page.js — Article schema
const articleSchema = {
  '@context': 'https://schema.org',
  '@type': 'Article',
  headline: post.title,
  description: post.excerpt,
  image: post.coverImage,
  datePublished: post.publishedAt,
  dateModified: post.updatedAt,
  author: {
    '@type': 'Person',
    name: post.author.name,
    url: post.author.url,
  },
  publisher: {
    '@type': 'Organization',
    name: 'Site Adı',
    logo: { '@type': 'ImageObject', url: 'https://www.example.com/logo.png' },
  },
};

4. Resim Optimizasyonu

// Next.js Image component
import Image from 'next/image';

// Otomatik optimizasyon, lazy loading, responsive
<Image
  src="/hero.jpg"
  alt="Açıklayıcı alt text — SEO için kritik"
  width={1200}
  height={630}
  priority       // LCP resminde kullanın
  quality={85}
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 1200px"
  placeholder="blur"
  blurDataURL="data:image/jpeg;base64,..."
/>

// next.config.js — Image yapılandırması
/** @type {import('next').NextConfig} */
module.exports = {
  images: {
    formats: ['image/avif', 'image/webp'],
    remotePatterns: [
      { protocol: 'https', hostname: 'cdn.example.com' },
    ],
    deviceSizes: [640, 750, 828, 1080, 1200, 1920],
    imageSizes: [16, 32, 48, 64, 96, 128, 256],
  },
};

5. URL Yapısı ve Yönlendirmeler

// next.config.js — Redirects ve rewrites
module.exports = {
  async redirects() {
    return [
      // www yönlendirmesi (Vercel'de otomatik)
      {
        source: '/:path*',
        has: [{ type: 'host', value: 'example.com' }],
        destination: 'https://www.example.com/:path*',
        permanent: true, // 301
      },
      // Eski URL'lerden yeni URL'lere
      {
        source: '/blog/old-post-url',
        destination: '/blog/new-post-url',
        permanent: true,
      },
      // Trailing slash tutarlılığı
      {
        source: '/blog/:slug/',
        destination: '/blog/:slug',
        permanent: true,
      },
    ];
  },

  // trailing slash yapılandırması
  trailingSlash: false,
};

6. Performans Optimizasyonları

// app/layout.js — Font optimizasyonu
import { Inter } from 'next/font/google';

const inter = Inter({
  subsets: ['latin', 'latin-ext'],
  display: 'swap',
  preload: true,
});

export default function RootLayout({ children }) {
  return (
    <html lang="tr" className={inter.className}>
      <body>{children}</body>
    </html>
  );
}
// Statik sayfalar için ISR
export const revalidate = 3600; // 1 saat

// Route segment config
export const dynamic = 'force-static'; // veya 'force-dynamic'

// Loading UI — UX ve Core Web Vitals
// app/blog/loading.js
export default function Loading() {
  return <div className="animate-pulse">Yükleniyor...</div>;
}

7. Erişilebilirlik (a11y) ve SEO

<!-- Semantik HTML kullanımı -->
<header>
  <nav aria-label="Ana navigasyon">
    <ul>
      <li><a href="/">Ana Sayfa</a></li>
      <li><a href="/blog">Blog</a></li>
    </ul>
  </nav>
</header>

<main>
  <article>
    <h1>Tek bir h1 — sayfa başlığı</h1>
    <p>İçerik...</p>
  </article>
</main>

<footer>
  <nav aria-label="Footer navigasyon">...</nav>
</footer>
İpucu: Her sayfada yalnızca bir adet <h1> kullanın. Heading hiyerarşisini (h1 > h2 > h3) doğru sıralayın. Bu hem erişilebilirlik hem de SEO için kritiktir.

8. SEO Kontrol Listesi Özeti

  • Metadata: Her sayfada benzersiz title ve description
  • Canonical URL: Her sayfada canonical tag
  • Sitemap: Dinamik sitemap.xml
  • Robots.txt: Doğru yapılandırma
  • Structured Data: JSON-LD schema markup
  • Open Graph: Sosyal medya kartları
  • Resim Optimizasyonu: Alt text, format, boyut
  • Core Web Vitals: LCP, INP, CLS hedefleri
  • HTTPS: Güvenli bağlantı
  • Mobil Uyumluluk: Responsive tasarım
  • URL Yapısı: Temiz, açıklayıcı URL'ler
  • Heading Hiyerarşisi: Tek h1, doğru sıralama
  • İç Linkleme: Anlamlı anchor text'ler
  • 404 Sayfası: Özel not-found sayfası
  • Yönlendirmeler: 301 redirect'ler
Uyarı: noindex meta tag'ını production'a deploy etmeden önce kaldırdığınızdan emin olun. Staging ortamlarında kullanılan robots: noindex production'da büyük SEO hasarına yol açar.

Sonuç

Next.js, SEO dostu uygulamalar geliştirmek için kapsamlı araçlar sunar. Metadata API ile dinamik meta tag'lar, sitemap ve robots.txt oluşturma, Image component ile resim optimizasyonu ve ISR ile güncel içerik sunma bu araçların başlıcalarıdır. Bu kontrol listesini projenizin başlangıcında uygulayarak SEO temellerini sağlam bir şekilde atabilirsiniz. Düzenli olarak Google Search Console ve PageSpeed Insights ile metriklerinizi izleyin.

Kaynaklar

İlgili Yazılar