Remix Sitemap: How to Generate an XML Sitemap
Remix Doesn't Include a Built-in Sitemap
Remix is a full-stack web framework built on web standards, but it does not ship with a sitemap generator. You need to add one yourself. There are two solid approaches: writing a custom resource route (recommended for full control), or using the remix-sitemap third-party package (faster to set up, convention-based).
A resource route in Remix is a route file that exports a loader (for GET) or action (for POST/PUT/DELETE) but no default component. When Remix matches the URL, it runs the loader and returns the response directly to the client. This makes resource routes ideal for generating XML, JSON feeds, RSS, or any non-HTML response.
Approach 1: Resource Route at sitemap[.]xml.tsx
Create the file app/routes/sitemap[.]xml.tsx. The square bracket notation in Remix escapes the dot so the route matches the literal URL /sitemap.xml. Without the brackets, Remix would treat the dot as a path separator.
Approach 2: Using the remix-sitemap Package
The remix-sitemap package provides a convention-based approach. Install it with npm install remix-sitemap. You then export a handle object with sitemap configuration from each route that should be included, and set up a central config file.
The package reads all routes with a handle.sitemap export and generates the XML automatically. For dynamic routes with real slugs, you need to implement a getSitemapEntries function that returns the actual URLs. See the remix-sitemap documentation for the full API.
Edge vs Node Runtime Considerations
Remix supports both Node.js and edge runtimes (Cloudflare Workers, Deno Deploy, Vercel Edge). The resource route approach works on both runtimes because it uses the standard Web Response API. Avoid using Node.js-specific APIs like fs inside your sitemap loader if you're targeting an edge runtime.
On Cloudflare Workers, database access typically goes through Cloudflare D1 (SQLite) or an external API. Fetch your dynamic URLs via HTTP or use bindings, not direct database connections. On Vercel, you can use Vercel KV or a standard database via an ORM like Prisma — but be mindful of cold start latency on serverless functions, which is why the CDN cache header (s-maxage=3600) matters.
Caching Your Sitemap for Performance
Generating a sitemap dynamically on every request is wasteful. Set aggressive CDN caching with s-maxage=3600 (cache at the CDN edge for 1 hour) combined with max-age=0 (no browser caching, so clients always get fresh CDN content). This means the first request per hour hits your server; subsequent requests are served from the CDN edge.
For content that changes infrequently, push s-maxage up to 86400 (24 hours) or even 604800 (1 week). For blogs with multiple daily posts, keep it at 3600. Google's crawler doesn't fetch your sitemap more than once every few hours anyway, so caching longer than that has no downside.
Submitting Your Remix Sitemap to Google Search Console
Once deployed, verify the sitemap returns valid XML at https://yourdomain.com/sitemap.xml. Then open Google Search Console, go to Indexing > Sitemaps, enter sitemap.xml, and click Submit. Google will queue it for processing. Add the sitemap URL to your robots.txt file as well: Sitemap: https://yourdomain.com/sitemap.xml — this ensures all crawlers can discover it even without GSC submission.