Back to roadmaps nextjs Course

Metadata and SEO Implementation

Search engine optimization (SEO) is a core strength of Next.js. In the App Router, you configure search crawler tags, browser headers, and social sharing OpenGraph card details using the built-in Metadata API.


1. Defining Static Metadata

For static pages, declare a metadata constant inside any server component page.tsx or layout.tsx file:

// src/app/about/page.tsx
import { Metadata } from "next";

export const metadata: Metadata = {
  title: "About Us | My Enterprise",
  description: "Learn more about our corporate team and core mission values.",
  openGraph: {
    title: "About Us | My Enterprise",
    description: "Learn more about our corporate team and core mission values.",
    images: ["/og-about.jpg"]
  }
};

export default function AboutPage() {
  return <h1>About Us</h1>;
}

2. Generating Dynamic Metadata

For dynamic routes (such as blog posts or product catalogs), you must generate metadata dynamically based on route parameter variables. Use the generateMetadata function helper:

// src/app/blog/[slug]/page.tsx
import { Metadata } from "next";

interface ProductProps {
  params: Promise<{ slug: string }>;
}

// Next.js executes this function before rendering the page HTML
export async function generateMetadata({ params }: ProductProps): Promise<Metadata> {
  const resolvedParams = await params;
  const slug = resolvedParams.slug;

  // Retrieve post details from database
  const post = await getPostDetails(slug);

  return {
    title: `${post.title} | Corporate Blog`,
    description: post.excerpt,
    openGraph: {
      images: [post.coverImage]
    }
  };
}

async function getPostDetails(slug: string) {
  // Mock API call
  return {
    title: "Next.js SEO Masterclass",
    excerpt: "Step-by-step metadata setup guide.",
    coverImage: "/og-blog-seo.jpg"
  };
}

export default function BlogPostPage() {
  return <article>Post content goes here...</article>;
}

3. Creating XML Sitemaps (sitemap.ts)

Sitemaps tell search engines which pages on your site are available for crawling. You can generate a dynamic sitemap.xml by creating a sitemap.ts file in the root of your app directory:

// src/app/sitemap.ts
import { MetadataRoute } from "next";

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const baseUrl = "https://example.com";

  // In production, fetch dynamic database slugs
  const posts = [{ slug: "hello-world" }, { slug: "nextjs-caching" }];

  const postUrls = posts.map(p => ({
    url: `${baseUrl}/blog/${p.slug}`,
    lastModified: new Date()
  }));

  return [
    {
      url: baseUrl,
      lastModified: new Date(),
      changeFrequency: "daily",
      priority: 1.0
    },
    {
      url: `${baseUrl}/about`,
      lastModified: new Date(),
      changeFrequency: "monthly",
      priority: 0.8
    },
    ...postUrls
  ];
}

4. Setting Search Rules (robots.ts)

Configure search engine crawl boundaries by adding a robots.ts file:

// src/app/robots.ts
import { MetadataRoute } from "next";

export default function robots(): MetadataRoute.Robots {
  return {
    rules: {
      userAgent: "*",
      allow: "/",
      disallow: "/admin/" // Block search crawlers from indexing the admin dashboard panel
    },
    sitemap: "https://example.com/sitemap.xml"
  };
}
Published on Last updated: