Sign up to the Blog

Brett Gamble's Blog

Welcome to your new favourite blog!

Rants and Raves | Books & Music | Full Stack Tech & More!

Brett Gamble

Next.js 13 - SEO with the App directory

April 10, 2023

Brett Gamble

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.