title template single source — don''t let children stamp the site name
title template single source
Browser tabs, SEO snippets, OG share cards — the same page often shows three different titles in three places. Cause is straightforward: the title template isn't composed from a single source, and pages also stamp the site name into their own title.
1. The duplication incident
[Root layout] title.template: "%s | SITE"
│
▼
[Child page A] title: "Pharmacy Search | SITE" ← stamps site name
│
▼ (auto-compose)
Browser tab → "Pharmacy Search | SITE | SITE"
N pages → N duplicates. SEO snippet truncates, OG card looks awkward, the tab is visually noisy. The pattern below is the cleanup after a 38-page outbreak of this.
2. Single-source rule
[Root layout] title.template: "%s | SITE"
│
▼ (auto-compose)
[Child page] title: "Pharmacy Search" ← site name 0 times
[Child page] title: "My Page"
[Child page] title: "Event Leaderboard"
Children write only their own title. The site name is stamped once by the root. Composition becomes "1 × 1 = 1", not "1 + 1 = 2".
3. SEO helpers fall into the same trap
Codebases often wrap <title> in a helper like generateSeoMetadata({title: "Pharmacy"}). The moment that helper does return { title: \${input} | SITE` }`, the same incident replays inside one function.
| Spot | Should NOT stamp site name |
|---|---|
| Root layout | Defines the template only |
Child page.tsx metadata.title |
No site name |
| SEO helper function | No site name (pass-through input) |
| Dynamic OG image generator | No site name |
The root is the only spot that stamps the site name. Everywhere else, "your own content only."
4. Before / after
| Aspect | N stamping spots | Single source |
|---|---|---|
| Browser tab | "Pharmacy | SITE | SITE" | "Pharmacy | SITE" |
| Site rename | Edit N spots | One line at the root |
| Cost per child page | Stamp the site name | Write your own title only |
| SEO snippet | Truncated (over the char limit) | Clean |
| OG card share | Awkward duplication | Clean |
5. Adopting this in your own project
-
grep -rn "| SITE" src/finds every child that stamps the site name. - Bulk-sed off the trailing
| SITE, including any leftover trailing space. - Hit the SEO helper function with the same sed.
- Code-review that the root layout's
title.templateis the single source. - Add a regression guard — a build-output check that fails when
SITE | SITE(double site name) appears.
A tab showing "SITE | SITE" looks small on its own, but it happens across N pages simultaneously — clean it up once, and pin the spot so it can't return.
More in cloud
All in this category →- GitHub Pages — host a repo as a static site
- Replit — Browser-based dev + deploy in one place
- HTTP API Mocking — WireMock · MockServer · Prism · MSW
- Firebase Local Emulator Suite — Running a Firebase Bundle on a Laptop
- Supabase Self-Hosted — Packing a BaaS into One Postgres Pot
- LocalStack and MiniStack — Emulating AWS Locally