No human being reads this site's sitemap.xml. It exists entirely for crawlers, gets zero direct visits worth counting, and if it silently broke tomorrow the only symptom would be a slow decline in indexing over weeks, with nothing in the site's own analytics pointing at the cause. That's exactly why it gets the same upgrade discipline as anything a person actually looks at, and the xmlsitemap 1.6.0 to 2.0.0 upgrade on this site is a real example of what that discipline looks like in practice.
Checking whether it's even needed before touching it
This site had four contrib modules from the same family in its Drupal 10 to 11 upgrade path: blazy, slick, inline_entity_form, and xmlsitemap. Only one of the four was actually enabled and doing real work — the other three got removed outright rather than upgraded, because dragging an unused dependency through a major-version bump for no reason is its own kind of risk. xmlsitemap was the one that stayed, which meant it was also the one that had to move to a release that supports Drupal 11.
What the version bump required
composer.json moved the constraint from drupal/xmlsitemap: ^1.5 to ^2.0. The resulting lock entry shows the real shift underneath that one-line change: xmlsitemap 2.0.0's own require block moved from drupal/core: ^9.3 || ^10 to ^10.3 || ^11, and its dev requirement on drupal/metatag moved from ^1.0 to ^2.0. This site was already on Drupal core 10.4.6 at the time, comfortably inside the new ^10.3 floor, so that part of the check was a formality. The part that wasn't a formality: 2.x removes functions that had been marked deprecated in 1.x for four years, and before running the upgrade I checked this site's own custom code for any direct call to an xmlsitemap_* function. There weren't any. If there had been, upgrading first and finding out during a fatal error afterward would have been the wrong order to do those two things in.
What configures this sitemap
The config in sync/ is small but specific. Articles and basic pages both carry priority: 0.5 in their xmlsitemap link settings — not the default 1.0, deliberately lower, since the front page is the only thing on this site set to frontpage_priority: 1.0. prefetch_aliases is on, so the sitemap emits each node's actual URL alias instead of its internal /node/123 path. An XSL stylesheet is enabled (xsl: 1) purely so the raw XML is readable in a browser rather than an unstyled wall of tags, which matters not at all to a crawler and only slightly to me, checking it by hand. Search engine notification is scoped to exactly one engine — engines: {google: google} — with a minimum_lifetime of 86400 seconds, so a burst of content changes in one day triggers at most one re-ping to Google in that window rather than one per change.
Testing something nobody will complain about if it's wrong
The upgrade commit's test list is deliberately mundane: drush updb and cache:rebuild both came back clean, drush config:status showed no drift, sitemap.xml still generated real content instead of an empty or error response, and a full pass through the site's JSON:API publish pipeline still worked end to end. None of those checks are exciting, and that's the point — a broken sitemap doesn't 404 loudly or throw a stack trace a human will see. It just quietly stops representing what's actually on the site, and a crawler either indexes a stale picture of it or deprioritizes crawling it further, with no error message pointed at the actual cause.
Why "nobody reads it" isn't the same as "it doesn't matter"
It would be easy to treat a machine-only file as lower stakes than anything rendered for a visitor, and by traffic volume, it obviously is. But the entire value of a sitemap is as an input to a system — search engine crawling — that this site has no direct visibility into and no error reporting from if that input goes stale or wrong. There's no analytics dashboard that says "your sitemap has been silently broken for six weeks." The only signal is indirect: pages not getting crawled, or getting crawled less often than they should. That absence of feedback is exactly the argument for checking the requirements, the deprecated-function list, and the actual output before and after the upgrade, rather than after — because if something had gone wrong, finding out wouldn't have happened on any timeline I'd control.