byandrev's blog
  • #astro

How to create a sitemap manually in Astro

3 min read

Structure of a Sitemap

A sitemap is an XML file that lists all the URLs of a website’s pages within a domain. It helps web crawlers, like those used by DuckDuckGo, Google, Yahoo, etc., find and index these pages.

Website structure and its sitemap
Website structure and its sitemap

Website structure and its sitemap

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    <url>
        <loc>http://www.yourdomain.com/</loc>
        <lastmod>2025-09-02</lastmod>
    </url>
</urlset>

In the sitemap structure, each URL must be placed inside a <url> tag. The page’s URL is defined in the <loc> tag, and the <lastmod> tag indicates the last time the page was updated.

Generating a Sitemap in Astro

To manually generate a sitemap in Astro, you need to create a file named sitemap.xml.ts or sitemap.xml.js and export a GET function like this:

export async function GET() {
  const siteUrl = import.meta.env.SITE;
 
  const result = `
  <?xml version="1.0" encoding="UTF-8"?>
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    <url>
        <loc>${siteUrl}/</loc>
    </url>
  </urlset>
  `.trim();
 
  return new Response(result, {
    headers: {
      "Content-Type": "application/xml",
    },
  });
}

It’s also worth noting that Astro offers the @astrojs/sitemap integration, which automatically generates the sitemap. Manual sitemap generation is only necessary when dealing with SSR (server-side rendered) pages, requiring a custom sitemap.

Don’t forget to add the following link to the <head> section of all your pages to indicate the path to your sitemap.xml:

<link rel="sitemap" href="/sitemap.xml" />

Now, let’s look at a more practical example. We’ll build a sitemap that includes the published articles of a blog.

import { getPosts } from "@/lib/posts";
 
export async function GET() {
  const siteUrl = import.meta.env.SITE;
  const posts = await getPosts();
 
  const result = `
  <?xml version="1.0" encoding="UTF-8"?>
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
      <url>
        <loc>${siteUrl}/</loc>
      </url>
 
    ${posts
      .map((post) => {
        const lastMod = post.updatedAt ?? post.createdAt;
 
        return `<url>
            <loc>${siteUrl}/blog/${post.slug}/</loc>
            <lastmod>${lastMod}</lastmod>
        </url>`;
      })
      .join("\n")}
 
  </urlset>
  `.trim();
 
  return new Response(result, {
    headers: {
      "Content-Type": "application/xml",
    },
  });
}

The code above will generate something like this:

Screenshot of the sitemap example in Astro
Screenshot of the sitemap example in Astro

Example of a sitemap

References