[GH-ISSUE #963] getMetadataRouteSuffix only exempts sitemap; metadataRouteSuffix also exempts robots and manifest #209

Closed
opened 2026-05-06 12:38:11 +02:00 by BreizhHardware · 1 comment

Originally created by @Divkix on GitHub (Apr 29, 2026).
Original GitHub issue: https://github.com/cloudflare/vinext/issues/963

Identified during review of #946.

Context

getMetadataRouteSuffix (static metadata URL resolution) only exempts sitemap from hash suffixes, while the existing metadataRouteSuffix (dynamic metadata URL resolution) exempts sitemap, robots, and manifest.

This is inconsequential today because robots and manifest are nestable: false (so they only appear at root, where there are no invisible parents to trigger hash suffixes). But if nestable ever changes, the two functions would disagree.

Suggested approach

Add robots and manifest exemptions to getMetadataRouteSuffix for defensive consistency, or add a comment noting why only sitemap is exempted (this function is ported from Next.js where robots/manifest aren't relevant in the static path).

Originally created by @Divkix on GitHub (Apr 29, 2026). Original GitHub issue: https://github.com/cloudflare/vinext/issues/963 Identified during review of #946. ## Context `getMetadataRouteSuffix` (static metadata URL resolution) only exempts `sitemap` from hash suffixes, while the existing `metadataRouteSuffix` (dynamic metadata URL resolution) exempts `sitemap`, `robots`, **and** `manifest`. This is inconsequential today because `robots` and `manifest` are `nestable: false` (so they only appear at root, where there are no invisible parents to trigger hash suffixes). But if `nestable` ever changes, the two functions would disagree. ## Suggested approach Add `robots` and `manifest` exemptions to `getMetadataRouteSuffix` for defensive consistency, or add a comment noting why only sitemap is exempted (this function is ported from Next.js where robots/manifest aren't relevant in the static path).
Author
Owner

@Divkix commented on GitHub (Apr 29, 2026):

Analysis

Compared vinext against Next.js source (packages/next/src/lib/metadata/get-metadata-route.ts).

Next.js (single function, lines 29–50)

Next.js has only one getMetadataRouteSuffix function. It exempts sitemap and nothing else:

if (page.endsWith('/sitemap') || page.endsWith('/sitemap.xml')) {
  return ''
}

There is no separate static/dynamic suffix function — Next.js uses the same function for both paths.

vinext (two functions)

vinext has two separate functions in packages/vinext/src/server/metadata-routes.ts:

  1. getMetadataRouteSuffix() (line 396) — used for static metadata routes (fillStaticMetadataSegment). Exempts only sitemap/sitemap.xml. Matches Next.js.

  2. metadataRouteSuffix() (line 463) — used for dynamic metadata routes. Exempts sitemap, robots, and manifest. Diverges from Next.js.

Verdict

  • The inconsistency is real but latent — robots and manifest are nestable: false (root-only) in vinext, so invisible parent segments never apply, and the extra exemptions are never triggered.
  • If nestable ever changes, the two functions would produce different suffixes for robots/manifest routes under invisible parents.

Align metadataRouteSuffix() with getMetadataRouteSuffix() and Next.js: remove the robots and manifest exemptions. Replace lines 463–468 with:

function metadataRouteSuffix(parentSegments: string[], metaType: string): string {
  if (metaType === 'sitemap') {
    return '';
  }
  // ... rest unchanged
}

This makes both functions match Next.js exactly and eliminates the inconsistency.

<!-- gh-comment-id:4347079949 --> @Divkix commented on GitHub (Apr 29, 2026): ## Analysis Compared vinext against Next.js source (`packages/next/src/lib/metadata/get-metadata-route.ts`). ### Next.js (single function, lines 29–50) Next.js has only one `getMetadataRouteSuffix` function. It exempts sitemap and nothing else: ```typescript if (page.endsWith('/sitemap') || page.endsWith('/sitemap.xml')) { return '' } ``` There is no separate static/dynamic suffix function — Next.js uses the same function for both paths. ### vinext (two functions) vinext has two separate functions in `packages/vinext/src/server/metadata-routes.ts`: 1. **`getMetadataRouteSuffix()`** (line 396) — used for *static* metadata routes (`fillStaticMetadataSegment`). Exempts only `sitemap`/`sitemap.xml`. **Matches Next.js.** ✓ 2. **`metadataRouteSuffix()`** (line 463) — used for *dynamic* metadata routes. Exempts `sitemap`, `robots`, **and** `manifest`. **Diverges from Next.js.** ✗ ### Verdict - The inconsistency is **real** but **latent** — robots and manifest are `nestable: false` (root-only) in vinext, so invisible parent segments never apply, and the extra exemptions are never triggered. - If `nestable` ever changes, the two functions would produce different suffixes for robots/manifest routes under invisible parents. ### Recommended Action Align `metadataRouteSuffix()` with `getMetadataRouteSuffix()` and Next.js: remove the `robots` and `manifest` exemptions. Replace lines 463–468 with: ```typescript function metadataRouteSuffix(parentSegments: string[], metaType: string): string { if (metaType === 'sitemap') { return ''; } // ... rest unchanged } ``` This makes both functions match Next.js exactly and eliminates the inconsistency.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#209
No description provided.