spatie/laravel-sitemap
Generate sitemaps for your Laravel site with ease. Crawl your entire site automatically or build sitemaps manually, add URLs with metadata like last modification dates, and split large crawls into multiple sitemap files.
Architecture fit
SitemapGenerator::create($url)) — walks the live site and discovers URLs. Fits legacy/irregular routing or apps where the URL space isn't cleanly derivable from models. It is also the higher-risk mode (see below).Sitemapable contract on Eloquent models) — each model returns its Url/route. Deterministic, testable, cheap, and the correct default for content-driven applications..getSitemap()->add(...) for model-backed sections.sitemapIndexPath), and maxTagsPerSitemap() further splitting into numbered files — this maps well onto a content-type-per-sitemap strategy and gives per-section indexing visibility in Google Search Console.Integration feasibility
composer require spatie/laravel-sitemap; optional config publish; no migrations, no schema changes, no auth surface. This is a low-blast-radius dependency.writeToDisk(..., public: true) in 7.1.0+) and a scheduler or queue worker for regeneration.Technical risk
lastmod correctness. A default now() was deliberately removed in 6.3.1, which is the right call but shifts responsibility to us: naive lastmod values degrade trust with crawlers. This is a correctness requirement, not a nice-to-have.spatie/crawler (v8 in 7.x) and symfony/dom-crawler 7. These constrain our PHP/Laravel upgrade windows and will surface as Renovate/Dependabot churn.hreflang/alternate-link emission, canonical de-duplication, automatic search-engine ping/submission (historically present, appears to have been removed), and robots.txt generation (out of scope).Key questions
hreflang? If yes, confirm whether the package emits alternates or we need a custom tag/renderer.Stack fit
spatie/crawler v8, symfony/dom-crawler 7. Confirm the exact support matrix against our pinned Laravel and PHP versions before committing.Migration path
/sitemap-new.xml) while the existing sitemap remains live and referenced in robots.txt.Sitemap: directive in robots.txt to the new index, keep the old path returning a 301 or removing it cleanly.Compatibility considerations
composer.json; these move together and Spatie has historically added new Laravel support promptly.public_path() vs a Laravel disk. Disk + public: true is preferable for containerized deploys where the filesystem is ephemeral — otherwise the sitemap vanishes on redeploy.Sequencing
Sitemapable on core models; single sitemap to the public disk; add a smoke test asserting schema validity and a minimum URL count.sitemapIndexPath; set maxTagsPerSitemap() for oversized sections.robots.txt update, GSC submission, baseline metrics captured.Maintenance
Sitemapable implementation, or it silently never gets indexed.Support
Scaling
Failure modes and mitigations
| Failure | Symptom | Mitigation |
|---|---|---|
| Crawl timeout / partial run | Truncated sitemap, silently written | Assert minimum URL count; fail the job loudly |
| WAF / bot protection blocks crawler | Empty or near-empty sitemap | Allowlist crawler UA, or use programmatic mode |
| Write/disk permission failure | 404 sitemap, GSC errors | Alert on missing file or stale mtime |
| Ephemeral filesystem on redeploy | Sitemap disappears after deploy | Write to persistent disk/S3, regenerate on deploy |
| Stale sitemap after content publish | New URLs never discovered | Trigger on publish events or post-deploy hook |
| Non-canonical/parameterized URLs included | Crawl budget waste, duplicate signals | Filter by canonical rules; use filter() on tags |
Naive lastmod values |
Crawler distrust of lastmod |
Derive from real updated_at, never now() |
Ramp-up
lastmod semantics, priority/changefreq (largely ignored by Google), sitemap index coverage, and GSC diagnostics. Budget roughly half a day of SEO stakeholder review of the generated output before launch, and treat that review as a gate rather than a post-launch cleanup.Acceptance criteria for go-live
How can I help you explore Laravel packages today?