Skip to main content
Frontend

SEO Basics for Server-Rendered Apps

10 min read

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:

typescript

Step 2 — Extend for blog posts

Add article type, publish date, and BlogPosting JSON-LD:

typescript

Step 3 — Wire head into each route

typescript

Step 4 — Generate a dynamic sitemap

Query published content and emit XML:

typescript

Step 5 — Add robots.txt

typescript

Expose as a server route returning text/plain.

Step 6 — Set BASE_URL in production

bash

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 with lastmod.
  • 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.