How to Fix: Unable to export metadata from a server page
Unable to export metadata from a server page in Next.js: why it breaks and how to fix it
This error usually appears when a page inside the App Router mixes incompatible exports or turns into a Client Component while still trying to export metadata. In Next.js, export const metadata is resolved on the server at build or request time, so the page must remain server-compatible.
Table of Contents
Understanding the Root Cause
In the Next.js App Router, metadata exports such as export const metadata and export async function generateMetadata() are part of the server rendering pipeline. That means Next.js expects them to live in a file that can be treated as a Server Component.
The issue happens when your page.jsx does one of the following:
- Adds
'use client'at the top of the file. - Imports a component that forces client-only behavior directly into the page module in a problematic way.
- Uses client-only hooks like
useState,useEffect, or browser globals such aswindowin the same file that exports metadata. - Combines unsupported exports with App Router page conventions.
Why this fails technically: Next.js performs static analysis on route modules. If a route file is marked as a Client Component, metadata cannot be exported from it because metadata generation is a server concern. Once the file becomes client-bound, Next.js throws an error similar to unable to export metadata from a server page or a related compiler error.
In short, metadata must stay on the server, while interactive UI must move into a separate client component.
Step-by-Step Solution
The safest fix is to keep src/app/page.jsx as a Server Component and move any interactive logic into a child component.
1. Remove 'use client' from the page file
If your page starts like this, it is the first thing to change:
'use client'
A page exporting metadata should not be a client component.
2. Keep metadata in the server page
Your page file should look like this:
export const metadata = {
title: 'Fictoan Docs',
description: 'Documentation site built with Next.js'
}
import HomePageClient from './HomePageClient'
export default function Page() {
return <HomePageClient />
}
This works because the route module remains server-compatible, and the interactive UI is delegated elsewhere.
3. Move client logic into a separate component
Create a new file such as src/app/HomePageClient.jsx:
'use client'
import { useEffect, useState } from 'react'
export default function HomePageClient() {
const [mounted, setMounted] = useState(false)
useEffect(() => {
setMounted(true)
}, [])
return (
<main>
<h1>Docs Home</h1>
<p>Mounted: {mounted ? 'yes' : 'no'}</p>
</main>
)
}
This separation is the core fix: server page for metadata, client child for interactivity.
4. If metadata depends on dynamic data, use generateMetadata()
When your title or description depends on fetched content, use the server-side metadata function:
export async function generateMetadata() {
const data = await fetch('https://example.com/api/docs', {
next: { revalidate: 60 }
}).then((res) => res.json())
return {
title: data.title,
description: data.description
}
}
import HomePageClient from './HomePageClient'
export default function Page() {
return <HomePageClient />
}
Use this only in server-compatible files. Do not place it in a client component.
5. Avoid browser-only APIs in the page module
If your page contains code like this, it can break server execution:
const theme = window.localStorage.getItem('theme')
Move that logic into a client component or run it inside useEffect in a file marked with 'use client'.
6. Validate imports
Even if the page itself does not use hooks, imported code can still cause trouble. Audit the page module and ensure that any client-only logic is isolated behind a separate component boundary.
export const metadata = {
title: 'Docs'
}
import Hero from './Hero'
import InteractiveSearch from './InteractiveSearch'
export default function Page() {
return (
<>
<Hero />
<InteractiveSearch />
</>
)
}
Then ensure InteractiveSearch is the client component, not the page itself:
'use client'
export default function InteractiveSearch() {
return <input placeholder="Search docs" />
}
7. Restart the dev server after refactoring
Next.js sometimes caches module boundaries aggressively during development. After moving files around, restart next dev to ensure the compiler re-evaluates the server/client split correctly.
Common Edge Cases
- Using both metadata export and client hooks in the same file: this is the most common cause and is never valid in App Router pages.
- Layout versus page confusion: metadata can also be exported from
layout.jsx. If shared metadata belongs to the entire route segment, move it there instead of duplicating it in the page. - Dynamic metadata with uncached fetches: if
generateMetadata()fetches data incorrectly, you may see build-time or runtime errors unrelated to the export itself. - Third-party components touching the browser at import time: some packages access
windowimmediately when imported. Wrap them in a client component and, if needed, load them with dynamic import. - Mixing Pages Router patterns with App Router: older
next/headusage or legacy route conventions can conflict with modern metadata handling. - Incorrect file placement: metadata exports only work in route segment files such as
page.jsxandlayout.jsx, not arbitrary utility files.
FAQ
Can I export metadata from a file that uses 'use client'?
No. A file marked with 'use client' is a Client Component, and metadata exports are server-only.
What is the correct pattern if my page needs both SEO metadata and interactive UI?
Keep the route file as a Server Component, export metadata or generateMetadata() there, and render a separate client component for interactive behavior.
Should I use metadata or generateMetadata()?
Use metadata for static values and generateMetadata() when the SEO fields depend on params, fetched content, or runtime conditions that still run on the server.
The durable fix for this GitHub issue is simple: do not let your page module become a client component if it needs to export metadata. Split responsibilities cleanly, and Next.js will handle both SEO and interactivity correctly.
For framework specifics, refer to the Next.js metadata documentation and the Client Components guide.