Skip to content
fearchitect
Quality, Observability & Cross-Cutting

SEO for Frontend

Rendering choices, metadata, structured data, and CWV for search ranking.

By Abas TurabliReviewed

Summary

Frontend decisions dominate SEO: CSR apps are crawlable but Google may delay rendering by days. SSR and SSG give crawlers HTML immediately. The Next.js Metadata API generates `<head>` tags at build or request time. JSON-LD structured data adds rich results. Core Web Vitals are a direct ranking signal for Google Search.

Jump to the interview angle

Rendering strategy vs crawlability

StrategyFirst-fetch HTMLGoogle indexing speedUse when
SSGFull HTML in CDN responseImmediate — no render queueContent is the same for all users
SSRFull HTML per requestImmediate — no render queueContent varies by user or URL
CSREmpty shell; JS builds DOMDelayed — JS render queueAuth-gated pages with no public SEO need
Partial prerenderingStatic shell + streamed dynamic slotsShell indexed immediatelyMostly static pages with a few dynamic sections

Next.js Metadata API + JSON-LD structured data

Next.js App Router exports metadata (static) or generateMetadata (dynamic, async). Add JSON-LD in the same file — Googlebot reads it from the initial HTML without executing extra JS.

Dynamic metadata and JSON-LD in an App Router pagetsx
import type { Metadata } from "next";

// generateMetadata runs on the server at request time.
export async function generateMetadata(
  { params }: { params: Promise<{ slug: string }> },
): Promise<Metadata> {
  const { slug } = await params;
  const post = await fetchPost(slug); // your data layer
  return {
    title: post.title,
    description: post.excerpt,
    alternates: { canonical: `https://example.com/blog/${slug}` },
    openGraph: {
      title: post.title,
      description: post.excerpt,
      images: [{ url: post.ogImage, width: 1200, height: 630 }],
    },
  };
}

// JSON-LD lives in the RSC layer → present in initial HTML.
export default async function BlogPost(
  { params }: { params: Promise<{ slug: string }> },
) {
  const { slug } = await params;
  const post = await fetchPost(slug);
  const schema = {
    "@context": "https://schema.org",
    "@type": "Article",
    headline: post.title,
    datePublished: post.publishedAt,
    author: { "@type": "Person", name: post.author },
  };
  return (
    <>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
      />
      <article>{/* … */}</article>
    </>
  );
}

generateMetadata and the page component share one fetchPost call — Next.js deduplicates it via fetch memoisation, so there is no double request.

Structural SEO checklist

  • Every public page needs a unique `<title>` and `<meta name="description">` — duplicates dilute ranking.
  • Set `<link rel="canonical">` on paginated, filtered, or UTM-tagged URLs to consolidate link equity.
  • Submit an XML sitemap to Google Search Console; exclude `noindex` URLs from it.
  • Keep `robots.txt` permissive for CSS, JS, and images — block only auth-gated paths.
  • Use semantic HTML (`<article>`, `<nav>`, `<main>`, `<h1>` hierarchy) — crawlers parse structure, not visual layout.

CWV are a ranking signal — INP is now included

Google's Page Experience signal includes all three Core Web Vitals: LCP (≤2.5 s), INP (≤200 ms), and CLS (≤0.1). INP replaced FID in March 2024. A poor INP from a heavy third-party script or a long event handler directly affects Search ranking for that URL. Measure with CrUX field data, not Lighthouse lab scores.

Interview angle

Expect questions on CSR vs SSR for crawlability, how Googlebot handles JS, and which CWV affect ranking. Soundbite: "Googlebot renders JS but queues it — SSR guarantees crawlers see your content on first fetch."

Key terms

SSR
Server-side rendering — HTML generated per request, visible to crawlers on first fetch.
JSON-LD
Script tag embedding schema.org structured data; enables rich results in Google Search.
canonical URL
The `<link rel="canonical">` tag that signals the authoritative URL for duplicate content.
Core Web Vitals
LCP, INP, CLS — Google ranking signals measuring load, responsiveness, and layout stability.

Further reading

Search fearchitect

Jump to a topic, mode, or action.