Skip to content
Back to posts

SEO in Next.js projects

April 7, 2024

When building modern web applications with React, developers often face challenges with search engine optimization (SEO). Traditional client-side rendered React apps deliver minimal HTML to browsers, requiring JavaScript execution before any meaningful content appears. This approach can hinder search engine crawlers, which may not execute JavaScript, resulting in poor indexing and low search rankings. Next.js, a popular React framework, addresses these SEO challenges by offering pre-renderng stategies, Metadata API and other performance optimizatin build into the framework. These features allow developers to pre-render pages on the server, delivering fully formed HTML to browsers and search engines. This article explores how Next.js enhances SEO for React applications and provides best practices for optimizing your Next.js projects for search engines.

Next.js gives you three core strategies—Server-Side Rendering (SSR), Static Site Generation (SSG), and Incremental Static Regeneration (ISR). All ship fully rendered HTML so search engines can crawl without running JavaScript, but each balances freshness, performance, and infrastructure cost differently.

With Next.js 16 you can easily create dynamic metadata, automatic image optimization, and structured data support. Metadata shapes how your pages appear in search results and social previews. Next.js 16's Metadata API allows you to define dynamic metadata for each page, including titles, descriptions, and Open Graph tags. This ensures that your content is accurately represented in search results and social media shares, improving click-through rates and overall SEO performance.

// app/layout.js
export const metadata = {
  title: { default: 'MySite', template: '%s | MySite' },
  description: 'Learning hub for modern web development',
  alternates: { canonical: 'https://mysite.com' }
};
// app/posts/[id]/page.js
export async function generateMetadata({ params }) {
  const post = await fetch(
    `https://somewebsite.com/posts/${params.id}`
  ).then((r) => r.json());

  return {
    title: `${post.name} | My Blog`,
    description: post.shortDescription,
    openGraph: { images: [post.image] },
    alternates: { canonical: `https://mywebsite.com/posts/${params.id}` }
  };
}

Open Graph and Twitter Card tags

Using Open Graph and Twitter Card tags you can decide what shows up when someone shares your link. You can declare them directly in the Metadata API:

export const metadata = {
  openGraph: {
    title: 'MySite – Full-stack tutorials',
    description: 'Step-by-step guides for modern web developers',
    url: 'https://mysite.com',
    type: 'website',
    images: ['/og-cover.png']
  },
  twitter: {
    card: 'summary_large_image',
    images: ['/og-cover.png']
  }
};

Sitemap generation

Creating sitemap and robots.txt files is essential for SEO. Next.js allows you to generate these files dynamically based on your site's structure, ensuring search engines can easily discover and index your content.

import { getBlogPosts } from "@/lib/utils-posts";

export const baseUrl = process.env.URL;

export default async function sitemap() {
	const posts = getBlogPosts().map((post) => ({
		url: `${baseUrl}/posts/${post.slug}`,
		lastModified: post.metadata.publishedAt,
	}));

	const routes = ["", "/posts", "contact"].map(
		(route) => ({
			url: `${baseUrl}${route}`,
			lastModified: new Date().toISOString().split("T")[0],
		}),
	);
	return [...routes, ...posts];
}

Performance optimizations

With Next.js Image tag you can optimize images to improve Core Web Vitals scorres, which are important for SEO. Next.js automatically serves appropriately sized images in modern formats, reducing load times and improving user experience. The component generates multiple source files and lets the browser choose the smallest one. It converts images to WebP or AVIF for lighter files and better LCP scores. Off-screen images wait until they enter the viewport, and explicit width/height prevents Cumulative Layout Shift.

import Image from 'next/image';

export default function Hero() {
  return (
    <Image
      src="/hero.jpg"
      alt="Developer working on a laptop"
      width={1280}
      height={720}
      priority
    />
  );
}

Structured data

JSON-LD turns raw HTML into machine-readable knowledge that powers rich snippets, product cards, and AI overviews. Next.js 16's Metadata API supports structured data, allowing you to define JSON-LD schemas for your pages. This helps search engines understand your content better and can enhance your search listings with rich results.

The recommended way to add structured data is to render it in a script tag with type application/ld+json in the layout or page component:

export default async function Page({ params }) {
  const { id } = await params
  const product = await getProduct(id)

  const jsonLd = {
    '@context': 'https://schema.org',
    '@type': 'Product',
    name: product.name,
    image: product.image,
    description: product.description,
  }

  return (
    <section>
      {/* Add JSON-LD to your page */}
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{
          __html: JSON.stringify(jsonLd).replace(</g, '\\u003c'),
        }}
      />
      {/* ... */}
    </section>
  )
}

To validate and test your structured data you can use Rich Results Test for Google or the generic Schema Markup Validator.

Conclusion

Next.js provides powerful tools and features to enhance SEO for React applications. By leveraging pre-rendering strategies, the Metadata API, Open Graph and Twitter Card tags, sitemap generation, performance optimizations, and structured data support, developers can create SEO-friendly websites that perform well in search engine rankings. Implementing these best practices in your Next.js projects can significantly improve your site's visibility and attract more organic traffic.