Next.js 13 - SEO with the App directory
April 10, 2023
Brett Gamble
Add SEO functionality to your Next.js 13 App directory application
Code Snippets
I was recently creating a new blog website and it required a level of SEO that I had not attempted before. I wanted to submit a dynamic site map (sitemap.xml) to assist Google to crawl and index my site. It needed to create a sitemap that contained paths to each page or blog post.
After a few attempts, I finally came up with the following code that works in Next.js 13 with the app directory.
The first thing we need to do is to create a new component called getSortedPostsData.js which I placed in a lib folder.
lib/getSortedPostsData.js
import {groq} from "next-sanity";
import {client} from '../lib/sanity.client';
export async function getSortedPostsData() {
const query = groq `*[_type=='post']
{
slug,
}`;
//
// const slugs: Post[] =await client.fetch(query)
const slugs = await client.fetch(query)
const slugRoutes = slugs.map((slug) => slug.slug.current);
// console.log('SlugRoutes', slugRoutes)
return slugRoutes.map(slug => ({
slug,
}))
}
What this code does is that it runs a Groq query to get all posts from my Sanity.io content management system. It then maps over each post and returns the slug which is the dynamic identifier used to uniquely identify each post.
The next step is to create a new route.tsx file inside a new directory within the app directory called sitemap.xml
app/sitemap.xml/route.tsx
import { getSortedPostsData} from '../../lib/getSortedPostsData';
const URL = "https://www.yourwebsite.com";
function generateSiteMap(posts) {
return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9">
<!--We manually set the URLs we know already-->
<url>
<loc>${URL}</loc>
</url>
<url>
<loc>${URL}/about</loc>
</url>
<url>
<loc>${URL}/blog</loc>
</url>
${posts
.map(({ slug }) => {
return `
<url>
<loc>${`${URL}/blog/post/${slug}`}</loc>
</url>
`;
})
.join("")}
</urlset>
`;
}
export async function GET() {
const posts = await getSortedPostsData();
const body = generateSiteMap(posts);
return new Response(body, {
status: 200,
headers: {
"Cache-control": "public, s-maxage=86400, stale-while-revalidate",
"content-type": "application/xml",
},
});
}
This file generates the sitemap when the you access it via:
- localhost://3000/sitemap.xml
- www.yourwebsite.com/sitemap.xml
The result is a new file that can be submitted to Google as a sitemap.