SEO Basics for Server-Rendered Apps
When someone shares your link on LinkedIn, the preview card comes from meta tags in your HTML. Google works the same way. If title and description only appear after JavaScript runs in the browser, many crawlers miss them entirely.
SSR puts metadata in the first HTML response — before React loads.
Vocabulary
| Term | Meaning |
|---|---|
| Meta tags | <title>, <meta name="description"> — shown in search results |
| Open Graph | og:* tags — control social preview cards |
| Canonical URL | Tells search engines the official page address |
| JSON-LD | Structured data block — enables rich search results |
| Sitemap | XML list of URLs you want indexed |
Steps
Step 1 — Build a reusable head helper
One function sets title, description, canonical, Open Graph, and Twitter cards:
Step 2 — Extend for blog posts
Add article type, publish date, and BlogPosting JSON-LD:
Step 3 — Wire head into each route
Step 4 — Generate a dynamic sitemap
Query published content and emit XML:
Step 5 — Add robots.txt
Expose as a server route returning text/plain.
Step 6 — Set BASE_URL in production
Every canonical link, sitemap entry, and OG URL derives from this — never hard-code localhost.
Common pitfalls
- Setting meta tags in
useEffect— crawlers never see them. - Forgetting
og:image— social shares show blank cards. - Static sitemap that never updates — new blog posts stay invisible to Google.
Verify it works
- View page source (not DevTools Elements) — meta tags must appear in raw HTML.
- Visit
/sitemap.xml— all published URLs listed withlastmod. - Test social cards at an Open Graph debugger.
- Validate JSON-LD with Google's Rich Results Test.
Takeaway
SEO is server-rendered metadata plus a sitemap that stays current. One head helper per page type, one env var for your domain, automatic sitemap from your database.