Adding a Sitemap to Your Next.js Site
Why You Need a Sitemap
Hey there! If you're building a Next.js site and want search engines to find all your content, you need a sitemap. It's like giving Google a map of your website - it helps them discover and index your pages faster. The best part? Next.js 13+ makes it super easy to create one.
The Quick Way
Next.js has a built-in way to generate sitemaps. Just create a sitemap.ts
file in your app
directory:
// app/sitemap.ts
import { MetadataRoute } from 'next';
export default function sitemap(): MetadataRoute.Sitemap {
return [
{
url: 'https://yoursite.com',
lastModified: new Date(),
changeFrequency: 'yearly',
priority: 1,
},
{
url: 'https://yoursite.com/about',
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.8,
},
{
url: 'https://yoursite.com/blog',
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.9,
},
];
}
That's it! Next.js will automatically create a /sitemap.xml
at the root of your site. But let's make it more interesting...
Making it Dynamic
The real power comes when you generate your sitemap dynamically based on your actual content. Here's how I do it with my blog posts and other dynamic content:
import { MetadataRoute } from 'next';
// Your data sources (could be from files, API, etc.)
interface BlogPost {
slug: string;
date: string;
}
async function getBlogPosts(): Promise<BlogPost[]> {
// Get your blog posts from wherever you store them
return [
{ slug: 'first-post', date: '2024-01-01' },
{ slug: 'second-post', date: '2024-01-15' },
];
}
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = 'https://yoursite.com';
// Get your dynamic content
const posts = await getBlogPosts();
// Start with your static routes
const routes: MetadataRoute.Sitemap = [
{
url: baseUrl,
lastModified: new Date(),
changeFrequency: 'yearly',
priority: 1,
},
];
// Add blog posts to sitemap
const postRoutes = posts.map(post => ({
url: `${baseUrl}/blog/${post.slug}`,
lastModified: new Date(post.date),
changeFrequency: 'monthly' as const,
priority: 0.7,
}));
return [...routes, ...postRoutes];
}
A Real-World Example
Here's how I handle multiple content types in my sitemap:
import { MetadataRoute } from 'next';
// Your content types
interface Page {
path: string;
lastMod?: Date;
}
interface BlogPost {
slug: string;
date: string;
}
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = 'https://yoursite.com';
// Static pages with their update frequency
const staticPages: Page[] = [
{ path: '', lastMod: new Date() }, // Home
{ path: '/about' }, // About
{ path: '/blog' }, // Blog index
{ path: '/projects' }, // Projects
];
// Get dynamic content
const posts = await getBlogPosts();
const products = await getProducts();
const routes: MetadataRoute.Sitemap = [
// Add static pages
...staticPages.map(page => ({
url: `${baseUrl}${page.path}`,
lastModified: page.lastMod || new Date(),
changeFrequency: 'monthly' as const,
priority: page.path === '' ? 1 : 0.8,
})),
// Add blog posts
...posts.map(post => ({
url: `${baseUrl}/blog/${post.slug}`,
lastModified: new Date(post.date),
changeFrequency: 'monthly' as const,
priority: 0.7,
})),
// Add products
...products.map(product => ({
url: `${baseUrl}/products/${product.id}`,
lastModified: new Date(product.updatedAt),
changeFrequency: 'weekly' as const,
priority: 0.9,
})),
];
return routes;
}
Pro Tips
Here are some things I've learned about sitemaps:
- Set
priority
based on importance - home page should be 1.0, less important pages lower - Use
changeFrequency
wisely - don't say daily if you rarely update the content - Keep your sitemap under 50,000 URLs (that's Google's limit)
- For bigger sites, create multiple sitemaps and a sitemap index (I'll cover that in another tutorial)
- Always include the lastModified date - it helps search engines know when to recrawl
Testing Your Sitemap
Once you've set it up, here's how to check if it's working:
- Visit
yoursite.com/sitemap.xml
- it should show your sitemap in XML format - Use the Google Search Console to submit your sitemap
- Check for any errors in the Search Console's sitemap report
Common Gotchas
Watch out for these common issues:
- Always use absolute URLs (https://yoursite.com/page), not relative ones (/page)
- The
changeFrequency
andpriority
fields are optional, but good to include - Don't forget to add your sitemap URL to your
robots.txt
file - Keep your dates in ISO format (the Date object handles this automatically)
Adding to robots.txt
Create a robots.txt
file in your public
folder:
# public/robots.txt
User-agent: *
Allow: /
# Add your sitemap URL
Sitemap: https://yoursite.com/sitemap.xml
Wrapping Up
That's it! You now have a dynamic sitemap that updates automatically with your content. Remember to submit it to search engines through their webmaster tools, and you're good to go! If you're handling lots of dynamic routes or need to split your sitemap into multiple files, check out my other tutorial on advanced sitemap techniques (coming soon).
Quick Tip: If your site has thousands of pages, consider caching the sitemap generation or using incremental static regeneration (ISR) to avoid regenerating it on every request.