Technology · Next.js

Next.js Metadata and SEO

Generate metadata, open graph tags, and improve SEO automatically.

TL;DR
  1. 01Export metadata constant to set page titles and descriptions.
  2. 02Use generateMetadata for dynamic metadata from data.
  3. 03Use Open Graph tags for social media sharing.

Static Metadata

  • Export metadata constant for static pages.
    import { Metadata } from "next";
    
    export const metadata: Metadata = {
      title: "About Us",
      description: "Learn more about our company and mission.",
      keywords: ["about", "company", "mission"]
    };
    
    export default function About() {
      return <div>About content</div>;
    }
  • Metadata sets HTML head tags automatically.
  • Improves SEO and social media sharing.
  • Use a layout-level metadata object to apply defaults across all pages.
    // app/layout.tsx
    export const metadata: Metadata = {
      title: { default: "My Site", template: "%s | My Site" },
      description: "Default description for all pages."
    };
  • Child page metadata merges with and overrides layout metadata.
    // app/about/page.tsx
    export const metadata: Metadata = {
      title: "About" // becomes "About | My Site" via template
    };

Dynamic Metadata

  • Generate metadata from data or parameters.
    import { Metadata } from "next";
    
    export async function generateMetadata({
      params
    }): Promise<Metadata> {
      const post = await getPost(params.slug);
      
      return {
        title: post.title,
        description: post.excerpt,
        authors: [{ name: post.author }]
      };
    }
    
    export default async function Post({ params }) {
      const post = await getPost(params.slug);
      return <article>{post.content}</article>;
    }
  • generateMetadata runs on the server.
  • Has access to params and other request data.
  • Fetch and cache data inside generateMetadata to avoid duplicate requests.
    export async function generateMetadata({ params }): Promise<Metadata> {
      const product = await getProduct(params.id); // Next.js deduplicates this fetch
      return { title: product.name, description: product.description };
    }
    export default async function Page({ params }) {
      const product = await getProduct(params.id); // same fetch, cached
      return <ProductDetail product={product} />;
    }
  • Return notFound() inside generateMetadata to trigger a 404 page early.
    export async function generateMetadata({ params }): Promise<Metadata> {
      const post = await getPost(params.slug);
      if (!post) notFound();
      return { title: post.title };
    }

Open Graph Tags

  • Set Open Graph tags for social sharing.
    export const metadata: Metadata = {
      title: "My Post",
      description: "Read my latest blog post",
      openGraph: {
        title: "My Post",
        description: "Read my latest blog post",
        url: "https://example.com/blog/my-post",
        siteName: "My Blog",
        images: [
          {
            url: "https://example.com/og-image.png",
            width: 1200,
            height: 630
          }
        ],
        type: "article"
      }
    };
  • Open Graph improves how links look on social media.
  • Include images for better engagement.
  • Use dynamic OG images with Next.js ImageResponse for per-page previews.
    // app/og/route.tsx
    import { ImageResponse } from "next/og";
    export async function GET(req: Request) {
      const { searchParams } = new URL(req.url);
      return new ImageResponse(<div>{searchParams.get("title")}</div>);
    }
  • Reference the dynamic OG route in your metadata image field.
    openGraph: {
      images: [`/og?title=${encodeURIComponent(post.title)}`]
    }

Twitter Card Tags

  • Add Twitter Card metadata for tweets.
    export const metadata: Metadata = {
      title: "My Post",
      description: "Read my latest blog post",
      twitter: {
        card: "summary_large_image",
        title: "My Post",
        description: "Read my latest blog post",
        images: ["https://example.com/og-image.png"],
        creator: "@myhandle"
      }
    };
  • Twitter Cards make tweets more engaging.
  • Use summary_large_image for best results.
  • Set twitter.site to your handle for attribution on shared links.
    twitter: {
      card: "summary_large_image",
      site: "@mycompany",
      creator: "@authorhandle"
    }
  • Reuse the same image URL for both OG and Twitter to reduce duplication.
    const ogImage = "https://example.com/og-image.png";
    export const metadata: Metadata = {
      openGraph: { images: [ogImage] },
      twitter: { images: [ogImage] }
    };

Structured Data

  • Add JSON-LD structured data for search engines.
    export default function BlogPost({ params }) {
      const post = getPost(params.slug);
      
      const schema = {
        "@context": "https://schema.org",
        "@type": "BlogPosting",
        headline: post.title,
        description: post.excerpt,
        image: post.image,
        author: {
          "@type": "Person",
          name: post.author
        },
        datePublished: post.date
      };
      
      return (
        <>
          <script
            type="application/ld+json"
            dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
          />
          <article>{post.content}</article>
        </>
      );
    }
  • Structured data helps search engines understand content.
  • Use schema.org types for consistency.
  • Add BreadcrumbList schema to help search engines show site hierarchy.
    const breadcrumb = {
      "@context": "https://schema.org",
      "@type": "BreadcrumbList",
      itemListElement: [
        { "@type": "ListItem", position: 1, name: "Home", item: "/" },
        { "@type": "ListItem", position: 2, name: "Blog", item: "/blog" }
      ]
    };
  • Validate structured data with Google's Rich Results Test tool before deploying.

Tip: Use generateMetadata with dynamic data to create unique, SEO-friendly titles and descriptions for each page.

Warning: Always include Open Graph images with correct dimensions (1200x630) to ensure proper display on social media.

Next.js Link and NavigationNext.js Performance Optimization