Blog

EN

How to create a sitemap manually in Astro

4 min read

A sitemap is a list of the pages on a website within a domain. You can usually find it on pages such as www.dominio.com/sitemap.xml. It is commonly used by web crawlers, such as search engines, to index web pages.

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

<?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

Example of a sitemap

References

Share this article on

Avatar byandrev

Andres Parra

Software Engineer

I'm Andres Parra, Software Engineer passionate about developing scalable and innovative technological solutions. I specialize in building modern web applications, mastering a versatile stack that includes JavaScript, TypeScript, Python, and Java, along with frameworks like React, Next.js, and Spring Boot. I'm also interested in the latest technologies and tools for development.