<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/dynamic-sitemap-xml-in-astro-ssr-1ivgasqks" -->

---
title: Dynamic sitemap.xml in Astro SSR | daily.dev
description: When using Astro in SSR mode (output: 'server'), the @astrojs/sitemap plugin doesn't work because there's no static build output. The solution is to create a...
canonical: https://daily.dev/posts/dynamic-sitemap-xml-in-astro-ssr-1ivgasqks
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Dynamic sitemap.xml in Astro SSR | daily.dev
og:description: When using Astro in SSR mode (output: 'server'), the @astrojs/sitemap plugin doesn't work because there's no static build output. The solution is to create a...
og:url: https://daily.dev/posts/dynamic-sitemap-xml-in-astro-ssr-1ivgasqks
og:image: https://api.daily.dev/og/posts/1IVgASqKs.png
og:image:alt: Dynamic sitemap.xml in Astro SSR
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Dynamic sitemap.xml in Astro SSR

**[Flavio Copes](https://daily.dev/sources/flaviocopes)** · 3 min read · 0 upvotes · 0 comments

## Summary

When using Astro in SSR mode (output: 'server'), the @astrojs/sitemap plugin doesn't work because there's no static build output. The solution is to create a sitemap.xml.ts API route that generates the sitemap at request time. The approach uses typed registries for static and data-driven pages, pure functions for XML building (making them unit-testable without Astro or Workers), and a 1-hour cache header. The same pattern applies to robots.txt. The trade-off is losing automatic lastmod and changefreq metadata, but for most apps just having correct loc entries is sufficient.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://flaviocopes.com/dynamic-sitemap-astro-ssr>

## Questions this post answers

### How do I generate a sitemap.xml for an Astro app that uses output: 'server' (SSR) instead of static build?

Create a sitemap.xml.ts file under your Astro pages directory that exports a GET handler returning an XML Response, since @astrojs/sitemap only works at build time and there's no dist/ output in SSR mode. Fetch dynamic slugs (e.g. via getCollection), build the URL list from typed registries of static paths plus data-driven entries, and generate the XML string with a pure function, caching the response with Cache-Control headers.

_Developers wiring up SSR routing edge cases like this often track Astro updates on daily.dev._

### Why doesn't @astrojs/sitemap work with Astro SSR mode?

The @astrojs/sitemap integration walks the build output in dist/ to generate a sitemap, but SSR apps with output: 'server' render pages on demand and produce no such build-time output, so there's nothing for the integration to scan. Instead, the sitemap must be built at request time by maintaining an explicit URL catalog in code and serving it from an API route.

_Teams weighing static versus SSR trade-offs in Astro can follow ecosystem changes on daily.dev._

## Similar posts on daily.dev

- [How Astro is built](https://daily.dev/posts/how-astro-is-built-vvxmcldse) · Flavio Copes · 2 upvotes · 0 comments
- [How to Build a Headless WordPress Frontend with Astro SSR on Cloudflare Pages](https://daily.dev/posts/how-to-build-a-headless-wordpress-frontend-with-astro-ssr-on-cloudflare-pages-30hassk3l) · freeCodeCamp · 3 upvotes · 0 comments
- [Astro 6.1](https://daily.dev/posts/astro-6-1-xxlqwjsn5) · Astro · 33 upvotes · 4 comments

---

Tags: [#webdev](https://daily.dev/tags/webdev), [#seo](https://daily.dev/tags/seo), [#cloudflare](https://daily.dev/tags/cloudflare), [#astro](https://daily.dev/tags/astro)

[View this post on daily.dev](https://daily.dev/posts/dynamic-sitemap-xml-in-astro-ssr-1ivgasqks)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Dynamic sitemap.xml in Astro SSR","url":"https://daily.dev/posts/dynamic-sitemap-xml-in-astro-ssr-1ivgasqks","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/dynamic-sitemap-xml-in-astro-ssr-1ivgasqks"},"datePublished":"2026-07-18T07:18:26.632Z","dateModified":"2026-09-14T08:57:09.644Z","description":"When using Astro in SSR mode (output: 'server'), the @astrojs/sitemap plugin doesn't work because there's no static build output. The solution is to create a...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/907c6c028f107fad7d0379f1571dde35?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/907c6c028f107fad7d0379f1571dde35?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Flavio Copes","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Flavio Copes","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/1f2dbd275797411bbd37bfdaaf0951a9","url":"https://daily.dev/sources/flaviocopes"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/dynamic-sitemap-xml-in-astro-ssr-1ivgasqks","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"webdev,seo,cloudflare,astro","timeRequired":"PT3M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Flavio Copes","item":"https://daily.dev/sources/flaviocopes"},{"@type":"ListItem","position":3,"name":"Dynamic sitemap.xml in Astro SSR"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/dynamic-sitemap-xml-in-astro-ssr-1ivgasqks#faq","mainEntity":[{"@type":"Question","name":"How do I generate a sitemap.xml for an Astro app that uses output: 'server' (SSR) instead of static build?","acceptedAnswer":{"@type":"Answer","text":"Create a sitemap.xml.ts file under your Astro pages directory that exports a GET handler returning an XML Response, since @astrojs/sitemap only works at build time and there's no dist/ output in SSR mode. Fetch dynamic slugs (e.g. via getCollection), build the URL list from typed registries of static paths plus data-driven entries, and generate the XML string with a pure function, caching the response with Cache-Control headers. Developers wiring up SSR routing edge cases like this often track Astro updates on daily.dev."}},{"@type":"Question","name":"Why doesn't @astrojs/sitemap work with Astro SSR mode?","acceptedAnswer":{"@type":"Answer","text":"The @astrojs/sitemap integration walks the build output in dist/ to generate a sitemap, but SSR apps with output: 'server' render pages on demand and produce no such build-time output, so there's nothing for the integration to scan. Instead, the sitemap must be built at request time by maintaining an explicit URL catalog in code and serving it from an API route. Teams weighing static versus SSR trade-offs in Astro can follow ecosystem changes on daily.dev."}}]}
```

