# Build a dynamic sitemap https://www.sanity.io/learn/course/seo-optimization/building-a-dynamic-sitemap.md A sitemap helps search engines understand and index your website more effectively. Generate a dynamic sitemap to guide search crawlers through your content, showing them what pages exist and how often they change. A well-structured sitemap gives search engines clear guidance about your content hierarchy and update frequency. ## Why this approach? Search engines like Google use sitemaps as a primary method to discover and understand your content. While they can crawl your site naturally through links, a sitemap: 1. Ensures all your content is discoverable, even pages that might be deep in your site structure 2. Helps search engines understand when content was last updated 3. Allows you to indicate content priority 4. Speeds up the indexing process for new content This is especially important for dynamic content managed through Sanity, where pages might be added or updated frequently. ## Learning objectives By the end of this lesson, you will: * Create a dynamic sitemap from Sanity content * Implement graceful validation error handling ### Understanding sitemaps Before diving into the code, let's understand what makes a good sitemap from a technical perspective: * **XML Format**: Search engines expect a specific XML format * **Last Modified Dates**: Helps search engines know when content was updated * **Change Frequency**: Indicates how often content changes * **Priority**: Suggests the importance of pages ### Building the sitemap Let's start with a GROQ query to fetch all `page` and `post` type documents. 1. **Update** `queries.ts` to include `SITEMAP_QUERY` ```typescript:src/sanity/lib/queries.ts // ...all other queries export const SITEMAP_QUERY = defineQuery(` *[_type in ["page", "post"] && defined(slug.current)] { "href": select( _type == "page" => "/" + slug.current, _type == "post" => "/posts/" + slug.current, slug.current ), _updatedAt } `) ``` This query: * Gets all documents of type `page` and `post` * Dynamically creates a complete path depending on the value of `_type` * Returns that path as `href`, and the last updated date of the document You've created a new query, so you'll need to create new types. ```sh:Terminal pnpm run typegen ``` The Next.js app router has a special, reserved route for generating an XML sitemap response from an array of objects in JavaScript. 1. See the Next.js documentation for more details on the [sitemap route](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap) The route below fetches content from Sanity using the query above, and generates the shape of content response that Next.js requires. 1. **Create** a new route to generate the sitemap ```typescript:src/app/sitemap.ts import { MetadataRoute } from "next"; import { client } from "@/sanity/lib/client"; import { SITEMAP_QUERY } from "@/sanity/lib/queries"; export default async function sitemap(): Promise { try { const paths = await client.fetch(SITEMAP_QUERY); if (!paths) return []; const baseUrl = process.env.VERCEL ? `https://${process.env.VERCEL_URL}` : "http://localhost:3000"; return paths.map((path) => ({ url: new URL(path.href!, baseUrl).toString(), lastModified: new Date(path._updatedAt), changeFrequency: "weekly", priority: 1, })); } catch (error) { console.error("Failed to generate sitemap:", error); return []; } } ``` ### Testing your sitemap After deploying your changes, you can test your sitemap by visiting [http://localhost:3000/sitemap.xml](http://localhost:3000/sitemap.xml) on your site. You should see something like this: ```xml http://localhost:3000/welcome-to-layer-caker 2025-01-10T14:13:34.000Z weekly 1 ``` Even if your sitemap looks correct, checking with a sitemap validator tool is recommended. Especially as your website grows. It's very easy to miss validation errors. A solid option is [XML Sitemaps](https://www.xml-sitemaps.com/validate-xml-sitemap.html) for a free and quick check. ### Best practices To ensure your sitemap is doing what it's meant to, keep these points in mind: * **Regular Updates**: Your sitemap should update when content changes * **Size Limits**: Keep under 50,000 URLs **per sitemap file** * **Valid URLs**: Ensure all URLs are properly formatted At this stage, your sitemap will now automatically update whenever you publish new content in Sanity, helping search engines discover and index your content. As you continue to enhance your sitemap implementation and expand out through other document types, you may want to consider adding different priorities for different page types to help search engines understand the relative importance of your content. Next, you'll explore structured data and JSON-LD, a clever way of reusing your documents for set-and-forget SEO benefits.