In this blog, I'll guide you through creating a sitemap within the Next.js pages router while using Sanity as a CMS and TypeScript for type safety. We will cover essentials like creating the sitemap type, adding a field to schemas include/exclude pages from appearing in the sitemap, setting up a query, and fetching data from Sanity.
Explaining sitemaps
When it comes to optimising your website for search engines, like Google and Bing, a well structured sitemap has a role to play. It helps out search engines in discovering your pages so they can be indexed and show up in search results. I can also be used a mode of navigation for your users, allowing them to more efficiently find content in your site.
Dependencies
Here is a list of the dependencies I used for this blog:
"next": "14.1.0"
"sanity": "3.26.1"
"next-sanity": "7.0.14"
Creating a sitemap TypeScript type
As I will be using TypeScript for this, I created the following type to ensure type safety. If you are using JavaScript, you can skip this.
types/index.ts
1importtype{Slug}from'sanity';
2
3exporttypeTSiteMap={
4 _type:string;
5 _updatedAt:Date;
6 slug?:Slug;
7};
Creating the query to fetch documents
Here is a basic query that can be used to fetch a set of documents and the required properties for to be displayed on the sitemap.
queries.ts
1import{ groq }from'next-sanity';
2
3exportconst sitemapQuery = groq`
4 *[_type == "page"] {
5 _updatedAt,
6 _type,
7 slug,
8 }
9`;
But there are a couple of improvements we can make to this query and our schemas to firstly make sure we are only fetching documents with a valid slug, turning the query into a function for reusability across multiple documents, and also give yourself or your editors the option to exclude the page from being indexed.
Fetching documents with a valid slug
This is a simple but effective change to add to your query as fetching a document without a valid slug and adding it to sitemap will not be great as it would cause your sitemap to be invalid and Google, or other search engines, might not be able to read it.
queries.ts
1exportconst sitemapQuery = groq`
2 *[_type == "page" && defined(slug)] {
3 _updatedAt,
4 _type,
5 slug,
6 }
7`;
Making a function for reusability
If you are like me and have multiple types of documents which eventually show up on the web, then coping and pasting the above query and changing the type each time is not only time wasting but you are repeating yourself which is not good practice.
I currently have a page, blog, service, and project schemas which all display a page on my frontend. The below is a massive time saver.
queries.ts
1exportconstsitemapQuery=(type:string)=>{
2return groq`
3 *[_type == "${type}" && defined(slug)] {
4 _updatedAt,
5 _type,
6 slug,
7 }
8`;
9};
Functionality to exclude pages from being indexed
Another neat thing we can do with Sanity is to give your editors or yourself the option to exclude certain pages from being indexed. One reason might be because you only want traffic to come from an external source like social media and see how it performs.
Here is my page document schema with a publish status string field which allows me to decide whether I want the page to be index.
page.ts
1import{ defineType }from'sanity';
2
3exportdefaultdefineType({
4 name:'page',
5 type:'document',
6 fields:[
7defineField({
8 title:'Publish status',
9 name:'publishStatus',
10 type:'string',
11 options:{
12 layout:'radio',
13 list:[
14{
15 title:"Hidden (won't show up in Google, but accessible through URL)",
16 value:'hidden',
17},
18'public',
19],
20},
21 initialValue:'hidden',
22}),
23...other fields,
24],
25});
Here's the updated query to only fetch those pages with a publish status value of public.
Now if you go to the route sitemap.xml on your site you should see your sitemap.
Validating the sitemap created
You can use an online tool such as Code Beautify to validate your sitemap. It let's you copy and paste your sitemap while you are developing to make sure your sitemap is valid before your deploy it to production.
Pushing the sitemap to Google Search Console
If you have not already, go create a Google Search Console account. As it says on the site, "tools and reports that help you measure your site's Search traffic and performance, fix issues and make your site shine in Google Search results".
Once you have created your account, or logged in, under Indexing click on Sitemaps. Enter in your sitemap and click submit.
Below is a screenshot from my Google Search Console, showing that one sitemap URL failed to be fetched while the other was a success. Only difference being a trailing slash.
At first I read this post in the Search Console Help community, the author mentions that it is fine and that Google just has not gotten to your sitemap yet. I waited a month no change...
Then while redoing my portfolio I found this issue on GitHub of others experiencing the same issue. One user suggested added a slash at the end, and what do you know it worked.
Conclusion
Generating a sitemap in not only your Next.js app is great step to take in optimising your website for search engines and improving overall user experience. Hopefully, by following this guide you would of been able to successfully generate a sitemap and submit it to Google Search Console for indexing.
If you were not able to achieve that, do not hesitate to get in touch with me and ask questions.