# How to Use React JS for SEO with Next.js: Server-Side Rendering and Metadata Control

> Boost your React JS SEO with Next.js. Learn how server-side rendering, static generation, and the generateMetadata API deliver SEO-friendly HTML to search engines.

- Repository: [Vercel/next.js](https://github.com/vercel/next.js)
- Tags: tutorial
- Published: 2026-02-16

---

**Next.js provides a full-stack rendering pipeline that sends fully rendered HTML—including all meta tags—to search engines before JavaScript executes, making React JS for SEO achievable through server-side rendering, static generation, and the `generateMetadata` API.**

Using React JS for SEO has historically challenged developers because client-side rendering hides content from search crawlers. Next.js, the React framework maintained by Vercel, solves this by giving you explicit control over the HTML document through server-side rendering and metadata management.

## Server-Side Rendering and Static Generation

The foundation of using React JS for SEO in Next.js lies in choosing the right rendering mode. When a page is rendered on the server or at build time, the complete HTML—including all `<head>` tags—is sent to the client before any JavaScript runs. Search bots index this HTML directly, making your metadata immediately discoverable.

Next.js supports three rendering strategies:

- **Static Generation**: HTML is generated at build time or on-demand using `generateStaticParams` and `revalidate`. The full HTML is cached and instantly served to crawlers.
- **Server-Side Rendering**: HTML is generated on each request using `generateMetadata` or `getServerSideProps`. This guarantees fresh metadata for dynamic titles and Open Graph tags.
- **Client-Side Rendering**: Content appears only after hydration. SEO works only if bots execute JavaScript, which is generally unreliable.

The core rendering pipeline lives in [`packages/next/src/server/app-render/app-render.tsx`](https://github.com/vercel/next.js/blob/main/packages/next/src/server/app-render/app-render.tsx). The framework creates a rendering span and calls your `generateMetadata` function before streaming HTML, ensuring metadata is "properly parented" in the initial payload【/tmp/instagit_geyfbtik/packages/next/src/server/app-render/app-render.tsx#L2676-L2677】.

## Managing Metadata with Head and generateMetadata

### The Head Component (Pages Router)

For the Pages Router, Next.js provides the `Head` component from `next/head`. This component collects all children and injects them into the document's `<head>` on the server. The implementation in [`packages/next/src/shared/lib/head.tsx`](https://github.com/vercel/next.js/blob/main/packages/next/src/shared/lib/head.tsx) validates usage and warns in development if you add disallowed elements like `<script>` or stylesheet `<link>` tags【/tmp/instagit_geyfbtik/packages/next/src/shared/lib/head.tsx#L30-L40】.

```tsx
import Head from 'next/head'

export default function BlogPost({ title, description }) {
  return (
    <>
      <Head>
        <title>{title}</title>
        <meta name="description" content={description} />
        <meta property="og:title" content={title} />
        <meta property="og:description" content={description} />
      </Head>
      <article>{/* content */}</article>
    </>
  )
}

```

### The generateMetadata API (App Router)

Next.js 13+ introduces the `generateMetadata` API for the App Router. Export an async `generateMetadata` function from a page or layout to compute titles, descriptions, Open Graph tags, and canonical URLs on the server before the HTML stream starts.

```tsx
// app/posts/[slug]/page.tsx
import type { Metadata } from 'next'

export async function generateMetadata({ params }: { params: { slug: string } }): Promise<Metadata> {
  const post = await fetchPost(params.slug)
  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      url: `https://example.com/posts/${params.slug}`,
    },
    alternates: {
      canonical: `https://example.com/posts/${params.slug}`,
    },
  }
}

```

## Critical SEO Pitfalls to Avoid

### Document Title Restrictions

Never place a `<title>` tag directly in your custom [`_document.tsx`](https://github.com/vercel/next.js/blob/main/_document.tsx) file. Next.js emits a development warning if you do, because titles belong in page-level `<Head>` components or `generateMetadata`. The check is implemented in [`packages/next/src/pages/_document.tsx`](https://github.com/vercel/next.js/blob/main/packages/next/src/pages/_document.tsx) around lines 620-628【/tmp/instagit_geyfbtik/packages/next/src/pages/_document.tsx#L620-L628】.

### Invalid Head Children

The `Head` component rejects `<script>` tags and stylesheet `<link>` tags. If you include these, Next.js warns you during development in [`packages/next/src/shared/lib/head.tsx`](https://github.com/vercel/next.js/blob/main/packages/next/src/shared/lib/head.tsx)【/tmp/instagit_geyfbtik/packages/next/src/shared/lib/head.tsx#L30-L40】. Use `next/script` for external scripts and import CSS directly or use `_document` for global stylesheets.

### Reliance on Client-Side Rendering

Client-only rendering delays content until after JavaScript executes. While Googlebot can execute JavaScript, many other search engines and social media crawlers do not run JavaScript reliably. Always use **Static Generation** or **Server-Side Rendering** for SEO-critical pages to ensure metadata appears in the initial HTML payload.

## Summary

- **Next.js** makes React JS for SEO achievable by rendering HTML on the server before sending it to crawlers.
- Use **Static Generation** for immutable content and **Server-Side Rendering** for dynamic data, ensuring metadata is included in the initial payload.
- Manage metadata with **`next/head`** in the Pages Router or **`generateMetadata`** in the App Router, both of which execute on the server.
- Avoid placing **`<title>`** in [`_document.tsx`](https://github.com/vercel/next.js/blob/main/_document.tsx) and never put **`<script>`** tags inside `next/head`.
- Reference the source implementation in [`packages/next/src/server/app-render/app-render.tsx`](https://github.com/vercel/next.js/blob/main/packages/next/src/server/app-render/app-render.tsx), [`packages/next/src/shared/lib/head.tsx`](https://github.com/vercel/next.js/blob/main/packages/next/src/shared/lib/head.tsx), and [`packages/next/src/pages/_document.tsx`](https://github.com/vercel/next.js/blob/main/packages/next/src/pages/_document.tsx) to understand how Next.js enforces these SEO patterns.

## Frequently Asked Questions

### Is React JS good for SEO?

React JS by itself relies on client-side rendering, which can hide content from search crawlers that do not execute JavaScript. However, when used with Next.js, React becomes fully SEO-capable because Next.js pre-renders HTML on the server, ensuring all content and metadata are visible to crawlers immediately.

### What is the difference between Head and generateMetadata?

The **`Head`** component from `next/head` is used in the Pages Router to inject tags into the document head through JSX composition. The **`generateMetadata`** API is an async function exported from App Router pages that runs on the server before streaming begins, allowing you to compute metadata from databases or APIs and return a structured metadata object.

### How does Next.js handle metadata for dynamic routes?

For dynamic routes in the App Router, you export an async `generateMetadata` function that receives the `params` object containing route segments. This function executes on the server during the rendering span defined in [`packages/next/src/server/app-render/app-render.tsx`](https://github.com/vercel/next.js/blob/main/packages/next/src/server/app-render/app-render.tsx), allowing you to fetch data specific to the slug or ID and return unique titles, descriptions, and Open Graph tags for each URL.

### Can I use client-side rendering for SEO-critical pages?

You should not rely on client-side rendering for pages where SEO is critical. While Googlebot can execute JavaScript, many other search engines and social media crawlers do not run JavaScript reliably. Next.js provides Static Generation and Server-Side Rendering specifically to ensure that SEO-critical metadata appears in the initial HTML payload without requiring client-side hydration.