Skip to the solution
MediumFrontend5 min read

How does Next.js handle SEO compared to a client-rendered SPA?

152 views

The problem

Question presented to candidate: "Why is Next.js considered better for SEO than a React single-page app, and what can still go wrong for SEO in a Next.js app?"

What a strong answer should cover:

  • A client-rendered SPA sends an almost empty HTML shell; content and titles appear only after JavaScript runs and data loads.
  • Next.js renders on the server (static, ISR, dynamic or PPR), so the first HTML already contains content, title, description and social tags.
  • Crawlers that do not run JavaScript, and social preview bots, see the full page; Google also indexes faster when it does not need to render.
  • Built-in helpers: Metadata API, opengraph-image, sitemap.ts, robots.ts, and structured data via JSON-LD.
  • It can still go wrong: client-only data fetching, missing metadataBase, content behind client components that fetch after load, and slow server responses.

Clarifying questions expected:

  • "Which pages need to rank?" β€” they must render their content on the server.
  • "Are social previews important?" β€” then metadata must be in the head for HTML-limited bots.

Code / implementation expected: Optional β€” the difference in the first HTML.

  • nextjs
  • seo
  • ssr
  • spa

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

5 min read Β· 8 sections

Read the code

The same product, client-fetched and server-rendered
// SPA-style: the HTML contains only "Loading..."
"use client";
import useSWR from "swr";
export function ProductClient({ slug }: { slug: string }) {
  const { data } = useSWR(`/api/products/${slug}`, (u) => fetch(u).then((r) => r.json()));
  return <h1>{data ? data.name : "Loading..."}</h1>;
}

// Next.js-style: the HTML contains the name and the head has the tags
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) {
  const p = await getProduct((await params).slug);
  return { title: p.name, description: p.summary };
}
export default async function ProductPage({ params }: { params: Promise<{ slug: string }> }) {
  const p = await getProduct((await params).slug);
  return <h1>{p.name}</h1>;
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 90 of 129 in Next.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Next.js questions
Up nextMedium

What runtimes does Next.js support (Node.js vs Edge runtime)?

Continue