Next.js Sitemap ve Robots.txt Oluşturma

Next.js Sitemap ve Robots.txt Oluşturma
Arama motorlarının sitenizi doğru ve verimli bir şekilde taraması için sitemap.xml ve robots.txt dosyaları kritik öneme sahiptir. Next.js App Router, bu dosyaları oluşturmak için yerleşik destek sunar. Bu yazıda statik ve dinamik sitemap oluşturmayı, robots.txt yapılandırmasını ve SEO en iyi pratiklerini adım adım inceleyeceğiz.
Robots.txt Nedir?
Robots.txt, arama motoru bot'larına sitenizin hangi bölümlerini tarayıp hangilerini atlayacağını bildiren bir dosyadır. Kök dizinde (/robots.txt) bulunmalıdır.
Statik robots.txt
# app/robots.txt (statik dosya)
User-Agent: *
Allow: /
Disallow: /api/
Disallow: /admin/
Disallow: /private/
Sitemap: https://example.com/sitemap.xml
Dinamik robots.txt
// app/robots.js
export default function robots() {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://example.com';
return {
rules: [
{
userAgent: '*',
allow: '/',
disallow: ['/api/', '/admin/', '/private/', '/_next/'],
},
{
userAgent: 'GPTBot',
disallow: '/',
},
{
userAgent: 'Googlebot',
allow: '/',
disallow: '/api/',
},
],
sitemap: `${baseUrl}/sitemap.xml`,
};
}
Sitemap Nedir?
Sitemap, arama motorlarına sitenizin tüm sayfalarını, güncelleme sıklığını ve önceliğini bildiren XML dosyasıdır. Büyük sitelerde arama motorlarının tüm sayfaları keşfetmesini kolaylaştırır.
Statik Sitemap
// app/sitemap.js
export default function sitemap() {
const baseUrl = 'https://example.com';
return [
{
url: baseUrl,
lastModified: new Date(),
changeFrequency: 'daily',
priority: 1.0,
},
{
url: `${baseUrl}/hakkimizda`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.8,
},
{
url: `${baseUrl}/blog`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.9,
},
{
url: `${baseUrl}/iletisim`,
lastModified: new Date(),
changeFrequency: 'yearly',
priority: 0.5,
},
];
}
Dinamik Sitemap (Veritabanından)
// app/sitemap.js
import { prisma } from '@/lib/prisma';
export default async function sitemap() {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL;
// Statik sayfalar
const staticPages = [
{ url: baseUrl, lastModified: new Date(), priority: 1.0 },
{ url: `${baseUrl}/hakkimizda`, lastModified: new Date(), priority: 0.8 },
{ url: `${baseUrl}/iletisim`, lastModified: new Date(), priority: 0.5 },
];
// Blog yazıları — veritabanından
const posts = await prisma.post.findMany({
where: { published: true },
select: { slug: true, updatedAt: true },
orderBy: { updatedAt: 'desc' },
});
const blogPages = posts.map((post) => ({
url: `${baseUrl}/blog/${post.slug}`,
lastModified: post.updatedAt,
changeFrequency: 'weekly',
priority: 0.7,
}));
// Ürünler — veritabanından
const products = await prisma.product.findMany({
where: { active: true },
select: { slug: true, updatedAt: true },
});
const productPages = products.map((product) => ({
url: `${baseUrl}/urunler/${product.slug}`,
lastModified: product.updatedAt,
changeFrequency: 'daily',
priority: 0.8,
}));
// Kategoriler
const categories = await prisma.category.findMany({
select: { slug: true },
});
const categoryPages = categories.map((cat) => ({
url: `${baseUrl}/kategori/${cat.slug}`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.6,
}));
return [...staticPages, ...blogPages, ...productPages, ...categoryPages];
}
Büyük Siteler İçin Sitemap Index
50.000'den fazla URL veya 50MB'dan büyük sitemap dosyaları için sitemap index kullanmalısınız:
// app/sitemap.js
export async function generateSitemaps() {
const totalProducts = await prisma.product.count();
const sitemapCount = Math.ceil(totalProducts / 50000);
// Her biri 50.000 URL içeren sitemap'ler
return Array.from({ length: sitemapCount }, (_, i) => ({ id: i }));
}
export default async function sitemap({ id }) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL;
const start = id * 50000;
const products = await prisma.product.findMany({
where: { active: true },
select: { slug: true, updatedAt: true },
skip: start,
take: 50000,
orderBy: { id: 'asc' },
});
return products.map((product) => ({
url: `${baseUrl}/urunler/${product.slug}`,
lastModified: product.updatedAt,
}));
}
// Bu, aşağıdaki URL'leri oluşturur:
// /sitemap/0.xml
// /sitemap/1.xml
// /sitemap/2.xml
// ve bir sitemap index dosyası
Çok Dilli Siteler İçin Sitemap
// app/sitemap.js
export default async function sitemap() {
const baseUrl = 'https://example.com';
const locales = ['tr', 'en', 'de'];
const posts = await getPosts();
const entries = posts.flatMap((post) =>
locales.map((locale) => ({
url: `${baseUrl}/${locale}/blog/${post.slug}`,
lastModified: post.updatedAt,
alternates: {
languages: Object.fromEntries(
locales.map((l) => [l, `${baseUrl}/${l}/blog/${post.slug}`])
),
},
}))
);
return entries;
}
Bu yapılandırma, aşağıdaki XML çıktısını üretir:
<url>
<loc>https://example.com/tr/blog/react-rehberi</loc>
<xhtml:link rel="alternate" hreflang="tr" href="https://example.com/tr/blog/react-rehberi" />
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/blog/react-rehberi" />
<xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/blog/react-rehberi" />
</url>
Google Search Console'a Sitemap Gönderme
- Google Search Console'a giriş yapın
- Sol menüden "Sitemaps" seçin
- Sitemap URL'ini girin:
https://example.com/sitemap.xml - "Gönder" butonuna tıklayın
- Durumun "Başarılı" olmasını bekleyin
Doğrulama ve Test
# Sitemap'i kontrol etme
curl https://example.com/sitemap.xml
# Robots.txt kontrol
curl https://example.com/robots.txt
# Google Search Console URL Denetim Aracı ile test
# Lighthouse SEO denetimi ile kontrol
Sonuç
Next.js App Router, sitemap.xml ve robots.txt oluşturmayı son derece kolaylaştırır. JavaScript fonksiyonları ile dinamik sitemap'ler oluşturabilir, veritabanından URL'leri çekebilir ve çok dilli siteler için hreflang desteği ekleyebilirsiniz. Büyük siteler için sitemap index yapısını kullanın, robots.txt ile crawl bütçenizi optimize edin ve Google Search Console ile sitemap'inizi takip edin. Bu adımlar, arama motorlarının sitenizi daha iyi anlamasını ve dizinlemesini sağlar.