How We Built a Dynamic Sitemap Generator in Next.js for SEO at Scale
The SEO Problem No One Talks About
You launch a Next.js app with great content, solid performance, and clean design. Then you realize: your sitemap is stale. Fast.
At AustinsElite, we faced this exact issue. Our site runs on Laravel 12 for the primary production backend (yes, not Next.js—that’s a common misconception), but our frontend uses a Next.js-based stack for dynamic content delivery and marketing pages. As we added more content, our static sitemap.xml became a maintenance burden. Every new page meant manual updates, and we were missing dynamic routes entirely. Search engines weren’t crawling everything, and we knew we were losing visibility.
The solution? A sitemap that builds itself—programmatically, on demand, and at scale.
Building the SitemapController: Automation with Intent
We created a SitemapController to dynamically enumerate all relevant routes and inject metadata like priority, change frequency, and last modified dates. This wasn’t just about listing pages—it was about signaling intent to search engines.
The controller pulls from multiple sources:
- Hardcoded core routes (e.g.,
/about,/contact) - Dynamic slugs from our Laravel API (e.g.,
/profile/[slug]) - Generated pages from CMS-backed content
Here’s a simplified version of how we structured it:
// pages/api/sitemap.ts
import { SitemapController } from '@/lib/sitemap';
export default async function handler(req, res) {
const sitemap = await SitemapController.generate();
res.setHeader('Content-Type', 'text/xml');
res.status(200).send(sitemap);
}
The real magic happens inside SitemapController.generate(). It uses async route resolution to fetch dynamic slugs from our Laravel 12 backend, applies weighting logic based on content freshness, and formats everything into valid XML with proper namespaces.
We didn’t want to hit the database on every request, so we added Redis-backed caching with a 1-hour TTL. For build-time generation, we also run a nightly job that pre-renders the sitemap as a static asset—giving us the best of both worlds: speed and freshness.
Integrating with Next.js: Build-Time Meets Runtime
Next.js gives us powerful tools, but combining static generation with dynamic data requires careful orchestration.
We use getStaticPaths and getStaticProps for our main content pages, but the sitemap sits at the intersection of build-time and runtime data. Our approach:
- At build time, generate a base sitemap for static pages
- At runtime, serve an enhanced version that includes recently updated dynamic content
- Use middleware to conditionally serve cached or fresh sitemaps based on query params (e.g.,
?preview=true)
This hybrid model ensures that crawlers always get a complete picture, even if some content was published after the last deploy.
We also added automatic lastmod tracking by tapping into our Laravel backend’s updated timestamps. No more guessing when a page changed—now it’s baked in.
Performance Wins and Crawlability Gains
Since rolling out the dynamic sitemap in June as part of our broader SEO stability push, we’ve seen measurable improvements:
- Googlebot crawl rate increased by ~35%
- Indexation of dynamic pages jumped from 60% to 98%
- Time to update sitemaps after content publish dropped from hours (manual) to seconds
But beyond the metrics, the real win is developer experience. We no longer have to remember to update the sitemap. It just works.
One unexpected benefit? The SitemapController became a de facto source of truth for route health. We now run automated checks against it to detect orphaned pages or broken dynamic patterns—turning SEO infrastructure into a debugging tool.
Final Thoughts
A sitemap might seem like a small piece of the puzzle, but it’s one of the first things search engines look at. Treating it as a first-class citizen—dynamic, fast, and accurate—has paid dividends in visibility and maintainability.
If you're running a Next.js app with growing content, don’t let your sitemap become technical debt. Build a system that scales with you. Ours does—and it’s helping AustinsElite stay discoverable, one auto-generated URL at a time.