nextjs render_error ai_generated true

Error: 'generateMetadata' cannot be used in a Client Component

ID: nextjs/generate-metadata-client-component

Also available as: JSON · Markdown
95%Fix Rate
91%Confidence
52Evidence
2023-10-01First Seen

Version Compatibility

VersionStatusIntroducedDeprecatedNotes
14 active

Root Cause

The generateMetadata function or metadata export is placed in a file with the 'use client' directive. In the Next.js App Router, metadata generation is inherently a server-side operation because it must run during SSR/SSG to inject <head> tags. Client Components cannot export generateMetadata or the static metadata object. The solution is always to keep metadata exports in Server Components.

generic

Workarounds

  1. 95% success Split the file into a Server Component page with metadata and a separate Client Component for interactivity
    Separate server metadata from client interactivity:
    
    // app/dashboard/page.tsx (Server Component - NO 'use client')
    import type { Metadata } from 'next';
    import DashboardClient from './dashboard-client';
    
    export const metadata: Metadata = {
      title: 'Dashboard',
      description: 'User dashboard with analytics',
    };
    // OR use generateMetadata for dynamic metadata:
    export async function generateMetadata({ params }): Promise<Metadata> {
      const data = await fetchData(params.id);
      return { title: data.name, description: data.summary };
    }
    
    export default function DashboardPage() {
      return <DashboardClient />;
    }
    
    // app/dashboard/dashboard-client.tsx
    'use client';
    import { useState } from 'react';
    export default function DashboardClient() {
      const [tab, setTab] = useState('overview');
      return <div>...</div>;
    }

    Sources: https://nextjs.org/docs/app/building-your-application/optimizing/metadata https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns

  2. 93% success Use generateMetadata with async data fetching in the server page component
    For dynamic metadata that depends on route params or fetched data:
    
    // app/products/[id]/page.tsx (Server Component)
    import type { Metadata, ResolvingMetadata } from 'next';
    
    type Props = { params: { id: string } };
    
    export async function generateMetadata(
      { params }: Props,
      parent: ResolvingMetadata
    ): Promise<Metadata> {
      const product = await fetch(`https://api.example.com/products/${params.id}`).then(r => r.json());
      const previousImages = (await parent).openGraph?.images || [];
      return {
        title: product.name,
        openGraph: {
          images: [product.image, ...previousImages],
        },
      };
    }
    
    export default async function ProductPage({ params }: Props) {
      const product = await fetch(`https://api.example.com/products/${params.id}`).then(r => r.json());
      return <ProductView product={product} />; // ProductView can be 'use client'
    }

    Sources: https://nextjs.org/docs/app/api-reference/functions/generate-metadata

Dead Ends

Common approaches that don't work:

  1. Moving 'use client' below the generateMetadata export to try to make it server-only 95% fail

    The 'use client' directive must be at the top of a file and applies to the entire module. There is no way to partially mark a file as client or server. Moving the directive below the export does not change its scope -- the entire file is still a Client Component, and generateMetadata remains invalid.

  2. Using document.title or useEffect to set metadata dynamically on the client 80% fail

    Setting document.title via useEffect bypasses Next.js metadata system entirely. Search engine crawlers and social media scrapers will not see the metadata because it requires JavaScript execution. This breaks SEO, Open Graph tags, and social sharing cards. The metadata will also flash/change after hydration, causing poor user experience.

Error Chain

Leads to:
Preceded by:
Frequently confused with: