DEV Community

Nana Okamoto
Nana Okamoto

Posted on

Practical Technical SEO in Next.js: The Implementation Guide

In the Next.js, SEO is built around Server Components and the Metadata API. This architecture ensures that your content is visible to search engines by default.

Here is the checklist of what you should implement for production-ready SEO.

1. Data Fetching in Server Components

By default, components in the app directory are Server Components. Fetching data here ensures that the final HTML sent to the browser (and crawlers) contains your content immediately.

// app/blog/[slug]/page.tsx
export default async function Page({ params }) {
  // Data is fetched on the server and rendered into HTML
  const post = await fetch(`https://api.example.com/posts/${params.slug}`).then(res => res.json())

  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </article>
  )
}
Enter fullscreen mode Exit fullscreen mode

2. The Metadata API

Use the built-in Metadata API to manage <title>, <meta>, and Open Graph tags.

Static Metadata
For pages with fixed content (e.g., Home, About).

// app/layout.tsx or app/page.tsx
export const metadata = {
  title: 'My App',
  description: 'The best app for SEO efficiency.',
}
Enter fullscreen mode Exit fullscreen mode

Dynamic Metadata
For dynamic routes like products or blog posts, use generateMetadata.

// app/products/[id]/page.tsx
export async function generateMetadata({ params }) {
  const product = await getProduct(params.id)

  return {
    title: product.name,
    description: product.description,
    alternates: {
      canonical: `https://example.com/products/${params.id}`,
    },
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Automated sitemap.xml

Instead of manually maintaining a XML file, use sitemap.ts to generate it dynamically.

// app/sitemap.ts
import { MetadataRoute } from 'next'

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const posts = await fetch('https://api.example.com/posts').then(res => res.json())

  const postEntries = posts.map((post) => ({
    url: `https://example.com/blog/${post.slug}`,
    lastModified: post.updatedAt,
  }))

  return [
    { url: 'https://example.com', lastModified: new Date() },
    ...postEntries,
  ]
}
Enter fullscreen mode Exit fullscreen mode

4. Robots Configuration

Use robots.ts to define crawling rules.

// app/robots.ts
import { MetadataRoute } from 'next'

export default function robots(): MetadataRoute.Robots {
  return {
    rules: {
      userAgent: '*',
      allow: '/',
      disallow: '/admin/',
    },
    sitemap: 'https://example.com/sitemap.xml',
  }
}
Enter fullscreen mode Exit fullscreen mode

5. Structured Data (JSON-LD)

Structured data helps search engines provide rich snippets. Inject it as a script tag inside your Server Component.

export default function Page({ post }) {
  const jsonLd = {
    "@context": "https://schema.org",
    "@type": "BlogPosting",
    headline: post.title,
    image: post.image,
    datePublished: post.date,
  }

  return (
    <section>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
      />
      <h1>{post.title}</h1>
    </section>
  )
}
Enter fullscreen mode Exit fullscreen mode

6. Image Optimization with priority

Large Contentful Paint (LCP) is a key SEO ranking factor. Use the priority property for your "Above the Fold" images (like Hero images) to tell Next.js to preload them.

import Image from 'next/image'

export default function Hero() {
  return (
    <Image
      src="/hero-banner.jpg"
      alt="Product Hero"
      width={1200}
      height={600}
      priority // Critical for LCP performance
    />
  )
}
Enter fullscreen mode Exit fullscreen mode

7. Environment-based Indexing

To prevent your staging or development sites from appearing in search results, toggle the robots metadata based on the environment.

export const metadata = {
  robots: {
    index: process.env.NODE_ENV === 'production',
    follow: process.env.NODE_ENV === 'production',
  },
}
Enter fullscreen mode Exit fullscreen mode

8. Verification

After deploying, always verify the raw HTML output. If you can see your keywords and metadata here, the crawlers can too.

curl -i https://your-domain.com/blog/my-post
Enter fullscreen mode Exit fullscreen mode

Summary Checklist

  1. Server Components: Keep data fetching on the server.
  2. Metadata API: Use it for titles, descriptions, and OG tags.
  3. File-based Metadata: Use sitemap.ts and robots.ts.
  4. JSON-LD: Add structured data for rich results.
  5. Image Priority: Use priority for LCP images.

Next.js App Router makes SEO highly efficient if you follow these server-first patterns. Focus on the initial HTML, and the rankings will follow.

Top comments (0)