FrontendPrep
Menu
Topics
Questions
Guides
Challenges
Soon
Back to Next.js Questions
nextjsEasy

Next.js: SEO, Metadata, and Social Graphs

Understand static and dynamic metadata, alternate canonical URLs, OpenGraph properties, sitemap generation, and SEO optimization in Next.js App Router.

Next.js: SEO, Metadata, and Social Graphs

A common Next.js interview question relating to search engines and shareability is:

How does Next.js handle SEO and search engine visibility in the App Router? Explain the difference between static and dynamic metadata, and how to configure sitemaps and canonical tags.

Search Engine Optimization (SEO) is a primary reason teams choose Next.js. The App Router provides a built-in Metadata API that makes managing titles, descriptions, canonical links, and social sharing tags simple and type-safe.


1. Static vs. Dynamic Metadata

Next.js lets you declare metadata in two ways:

A. Static Metadata (Static Export)

If a page's metadata does not depend on dynamic data (like an ID in the URL), you can export a static metadata object from a page.tsx or layout.tsx file:

import type { Metadata } from 'next';
 
export const metadata: Metadata = {
  title: 'Home Page | Frontend Prep',
  description: 'Master senior-level frontend interview questions.',
};
 
export default function Page() {
  return <h1>Welcome to Frontend Prep</h1>;
}

B. Dynamic Metadata (generateMetadata)

If your metadata depends on dynamic parameters (such as an API query or database lookup), you must export a generateMetadata function. Next.js runs this function before rendering the page:

import type { Metadata } from 'next';
 
type Props = {
  params: Promise<{ id: string }>;
};
 
export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const { id } = await params;
  const product = await fetchProduct(id);
 
  return {
    title: `${product.title} | Store`,
    description: product.description,
    openGraph: {
      images: [{ url: product.imageUrl }],
    },
  };
}

Next.js automatically deduplicates fetch calls within generateMetadata and the main Page component, so you can fetch the same product data in both places without performance penalties.


Canonical links prevent search engines from index-duplicating similar URLs, while OpenGraph properties control how cards look when shared on Slack or Twitter.

export const metadata: Metadata = {
  alternates: {
    canonical: 'https://frontendprep.com/questions/javascript/closures',
  },
  openGraph: {
    title: 'JavaScript Closures Explained',
    description: 'Learn closures from first principles.',
    url: 'https://frontendprep.com/questions/javascript/closures',
    siteName: 'Frontend Prep',
    type: 'article',
    images: [
      {
        url: 'https://frontendprep.com/og-image.png',
        width: 1200,
        height: 630,
      },
    ],
  },
};

3. Automated Sitemaps (sitemap.ts)

Instead of writing static XML sitemaps, Next.js lets you generate them dynamically. By creating a sitemap.ts file in the root of your app/ directory, you can dynamically build search maps:

// app/sitemap.ts
import { MetadataRoute } from 'next';
import { getAllQuestions } from '@/lib/mdx';
 
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const baseUrl = 'https://frontendprep.com';
  const questions = getAllQuestions();
 
  const questionUrls = questions.map((q) => ({
    url: `${baseUrl}/questions/${q.category}/${q.slug}`,
    lastModified: new Date(),
    changeFrequency: 'weekly' as const,
    priority: 0.8,
  }));
 
  return [
    {
      url: baseUrl,
      lastModified: new Date(),
      changeFrequency: 'daily',
      priority: 1.0,
    },
    ...questionUrls,
  ];
}

Senior-Level Interview Answer

Next.js coordinates search-engine visibility in the App Router using a built-in Metadata API that merges layout and page definitions during rendering. For static routes, we export a structured metadata object, while dynamic routes use the generateMetadata function to resolve metadata properties (such as titles, alternates, and openGraph schemas) asynchronously from routing parameters. Internally, Next.js deduplicates fetch queries across generateMetadata and Page rendering components to prevent double-fetching overhead. For index optimization, sitemaps are generated dynamically by exporting a default function from app/sitemap.ts that maps database entities into standardized MetadataRoute.Sitemap XML nodes.


Common Interview Mistakes

❌ Redefining metadata in Client Components

You cannot export metadata or generateMetadata from Client Components ("use client"). They must reside in Server Components to ensure search crawlers can parse them easily from the initial server-rendered HTML payload.

❌ Double-fetching data manually

Assuming you need to write complex cache layers to pass product details from generateMetadata to the main Page component. Next.js overlays standard fetch requests with an automatic caching layer, meaning calling fetch() with the same parameters twice results in a single network request.


Key Takeaways

  • Metadata Separation: Static metadata objects are exported for simple pages; dynamic pages use generateMetadata to fetch SEO properties.
  • Query Deduplication: Double data fetches between generateMetadata and Page render components are automatically deduplicated.
  • Canonical Alternates: Always declare alternates/canonical links inside the metadata schema to prevent content duplicate indexing.
  • Server Only: Metadata export functions are executed on the server and are invalid inside Client Components ("use client").
  • Dynamic Sitemaps: Use app/sitemap.ts to query DB data and export XML sitemaps to coordinate search index updates.

Share this Resource

Help other developers level up by sharing this study guide.

More Technical Questions

Expand your mastery. Deep dive into other frontend interview challenges in this category.