cloudflare / cloudflare/vinext
Metadata: parent title.template is applied to a page-level string title (Next treats it as absolute)
- Dominant language
- TypeScript
- Stars
- 8.8k
- Forks
- 406
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 120
Description
### What happened
vinext applies a parent layout's `title.template` to a page that exports a **plain string** `title`. Next.js 16 treats a page-level string title as absolute and does **not** apply the parent template, so the site name ends up duplicated under vinext.
```
Next.js 16.3.2 Home | Devfive
vinext Home | Devfive | Devfive
Next.js 16.3.2 홈 | 데브파이브
vinext 홈 | 데브파이브 | 데브파이브
```
Only the two root routes (`/en/`, `/ko/`) differ; other routes match, because only these set a page-level string title.
### Reproduction
`app/[lang]/layout.tsx`
```ts
export async function generateMetadata(): Promise {
return {
title: {
default: 'Devfive',
template: '%s | Devfive',
},
}
}
```
`app/[lang]/page.tsx`
```ts
export async function generateMetadata(): Promise {
return { title: 'Home | Devfive' }
}
```
- Next.js renders `Home | Devfive` — the string is absolute, template skipped.
- vinext renders `Home | Devfive | Devfive` — template applied on top.
Our application deliberately writes the full title at page level precisely because Next 16 does not apply the template there (we have a code comment saying so, added while fixing an accessibility requirement for unique page titles). Under vinext that workaround double-applies.
### Expected
Match Next.js: a page-level `title: string` is absolute; the parent `title.template` applies only to `title.default` resolution for child segments that do not set their own title, and to `title: { absolute: ... }` / nested title objects per the Metadata API rules.
### Why it matters
`` is user-visible in the tab and in search results, so this is an SEO/UX regression rather than a cosmetic difference. It was caught by a golden-master diff comparing SSR HTML between the two runtimes.
### Environment
- vinext 1.0.0-beta.8, Vite 8.2.2
- Next.js 16.3.2 API surface, App Router, `generateMetadata`
- `next-intl` for localization (the title strings come from a plain record, not from next-intl, so the plugin is not involved)
- `--platform=node`, `output: 'standalone'`
Contributor guide
Research direction
Start with the reproduction in app/[lang]/layout.tsx and app/[lang]/page.tsx, then compare the SSR title output with Next.js 16.3.2. Trace vinext's metadata resolution for page-level string titles and parent templates. Done means /en/ and /ko/ produce the same non-duplicated titles as Next.js while other routes remain unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- nextjs, typescript
- Domain
- web-dev
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100