How to fix headers() can only be called in a Server Component in React
This error occurs when attempting to use Next.js's headers() function inside a Client Component. The headers() function is a server-only API that reads incoming HTTP request headers and can only be called in Server Components.
Quick fix
Fixes headers() can only be called in a Server Component
grep -r "from 'next/headers'" src/
grep -r "from \"next/headers\"" src/- Identify where headers() is being called
- Move headers() call to a Server Component
- Pass headers as props from Server to Client Component
- Extract server-only code into separate files
grep -r "from 'next/headers'" src/grep -r "from \"next/headers\"" src/headers() can only be called in a Server Component
What this error means
This error indicates that you're trying to use the headers() function from next/headers in a Client Component. In Next.js 13+ with the App Router, the headers() function is a server-only API that allows you to read HTTP incoming request headers. It's designed to work exclusively in Server Components because it accesses server-side request data that isn't available in the client-side JavaScript bundle. The headers() function is an async function that extends the Web Headers API and provides methods like get(), has(), and forEach() to access request headers such as user-agent, referer, cookie, and authorization. Since it's a Dynamic API whose returned values cannot be known ahead of time, using it opts a route into dynamic rendering at request time rather than static generation. This restriction exists for security and architectural reasons. Request headers contain sensitive information that should be processed on the server. Client Components run in the browser and cannot directly access server request objects. Mixing server-only code with client code would break the component boundary model that Next.js enforces to maintain clear separation between server and client execution contexts.
Typical symptoms
- Runtime error message stating "headers() can only be called in a Server Component"
- Error appears when using "use client" directive in a file that calls headers()
- Build succeeds but application crashes at runtime when the component renders
- Error occurs when importing a utility function that uses next/headers into a Client Component
- TypeScript or ESLint shows no warnings but runtime fails with headers() error
- Error happens after converting a Server Component to Client Component to add interactivity
- Application works in development but fails in production with headers() error
Common causes
- Directly calling headers() function inside a component marked with "use client" directive
- Importing a shared utility function or module that internally uses next/headers into a Client Component
- Converting a Server Component to Client Component without removing headers() calls
- Using headers() in a component that has client-side interactivity like onClick handlers or useState
- Calling headers() inside a context provider that's used in both server and client components
- Importing next/headers in a file that gets bundled into the client-side JavaScript
- Using headers() in middleware or API route handlers incorrectly wrapped in client code
- Attempting to access request headers in browser-side event handlers or effects
How to fix "headers() can only be called in a Server Component"
Search your codebase for imports from "next/headers" and locate all usage of the headers() function. Check if the file contains a "use client" directive at the top. Use your IDE's find-in-files feature:
grep -r "from 'next/headers'" src/
grep -r "from \"next/headers\"" src/Or search for the "use client" directive in files that import headers:
grep -l "use client" src/**/*.tsx | xargs grep "next/headers"Once you identify the problematic file, verify whether it needs to be a Client Component or if it can remain a Server Component.
If the component doesn't require client-side interactivity (no useState, useEffect, onClick, etc.), remove the "use client" directive to make it a Server Component:
// ❌ Before - Client Component trying to use headers()
"use client";
import { headers } from "next/headers";
export default function MyComponent() {
const headersList = await headers();
const userAgent = headersList.get("user-agent");
return <div>User Agent: {userAgent}</div>;
}
// ✅ After - Server Component with headers()
import { headers } from "next/headers";
export default async function MyComponent() {
const headersList = await headers();
const userAgent = headersList.get("user-agent");
return <div>User Agent: {userAgent}</div>;
}Note that Server Components must be async functions when using await with headers().
If your component needs client-side interactivity, create a Server Component wrapper that reads headers and passes the needed values as props to your Client Component:
// app/page.tsx (Server Component)
import { headers } from "next/headers";
import ClientComponent from "./ClientComponent";
export default async function Page() {
const headersList = await headers();
const userAgent = headersList.get("user-agent") || "unknown";
const referer = headersList.get("referer") || "";
return <ClientComponent userAgent={userAgent} referer={referer} />;
}
// ClientComponent.tsx (Client Component)
"use client";
import { useState } from "react";
interface Props {
userAgent: string;
referer: string;
}
export default function ClientComponent({ userAgent, referer }: Props) {
const [count, setCount] = useState(0);
return (
<div>
<p>User Agent: {userAgent}</p>
<p>Referer: {referer}</p>
<button onClick={() => setCount(count + 1)}>Count: {count}</button>
</div>
);
}Only pass the specific header values needed—never pass the entire headers object to maintain security.
If you have utility functions that use headers(), isolate them in separate files and mark them as server-only to prevent accidental client-side imports:
// lib/server-utils.ts
import "server-only"; // Install: npm install server-only
import { headers } from "next/headers";
export async function getUserAgent() {
const headersList = await headers();
return headersList.get("user-agent") || "unknown";
}
export async function getAuthToken() {
const headersList = await headers();
return headersList.get("authorization");
}The "server-only" package will throw a build-time error if this file is accidentally imported in a Client Component. Install it with:
npm install server-onlyThen import only in Server Components:
// app/dashboard/page.tsx (Server Component)
import { getUserAgent } from "@/lib/server-utils";
export default async function Dashboard() {
const userAgent = await getUserAgent();
return <div>Detected: {userAgent}</div>;
}If you need to access headers for authentication, redirects, or request processing that applies across multiple routes, use Next.js middleware instead:
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
const userAgent = request.headers.get("user-agent") || "";
const authToken = request.headers.get("authorization");
// Add custom headers to the response
const response = NextResponse.next();
response.headers.set("x-user-agent", userAgent);
// Or redirect based on headers
if (!authToken && request.nextUrl.pathname.startsWith("/dashboard")) {
return NextResponse.redirect(new URL("/login", request.url));
}
return response;
}
export const config = {
matcher: ["/dashboard/:path*", "/api/:path*"],
};Middleware runs on the Edge Runtime and can access request headers before any component renders.
For API endpoints that need header access, use the request object directly in Route Handlers rather than the headers() function:
// app/api/user-info/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const userAgent = request.headers.get("user-agent");
const authorization = request.headers.get("authorization");
return NextResponse.json({
userAgent,
hasAuth: !!authorization,
});
}API Route Handlers receive the request object as a parameter, giving you direct access to headers without needing the headers() function.
Check that your component hierarchy properly separates server and client components. Run your development server and check for any warnings:
npm run devNext.js will show warnings like:
You're importing a component that needs next/headers.
That only works in a Server Component but one of its parents is marked with "use client"Restructure your component tree so Server Components that use headers() are not children of Client Components. The pattern should be:
Server Component (uses headers())
└─> Client Component (receives props)
└─> More Client ComponentsNot:
Client Component
└─> Server Component (uses headers()) ❌ InvalidAdvanced notes
The headers() function is implemented as a Dynamic API that opts routes into dynamic rendering at request time. This means pages using headers() cannot be statically generated during build time. If you need static generation while conditionally accessing headers, consider using middleware to set custom headers that can be read by static pages without opting into dynamic rendering.
When passing headers to Client Components, be mindful of security implications. Never expose sensitive headers like authorization tokens, cookies, or API keys directly in props that will be serialized to the client-side bundle. Instead, use these headers on the server to fetch data or make decisions, then pass only the resulting data or boolean flags to Client Components.
The headers() function extends the Web Headers API, so it returns a Headers object with standard methods like get(), has(), entries(), keys(), and values(). You can iterate over headers using forEach() or convert them to an array using Array.from(headersList.entries()).
For TypeScript users, the headers() function returns Promise<ReadonlyHeaders> in Next.js 13+. The ReadonlyHeaders type indicates you cannot modify these headers—they're read-only representations of the incoming request. To set response headers, use NextResponse in middleware or API routes.
In Pages Router (Next.js 12 and earlier), you would access headers through getServerSideProps context object (context.req.headers) instead of the headers() function. The headers() function is specific to the App Router introduced in Next.js 13.
Frequently asked questions
- What does "headers() can only be called in a Server Component" mean?
- This error indicates that you're trying to use the headers() function from next/headers in a Client Component. js 13+ with the App Router, the headers() function is a server-only API that allows you to read HTTP incoming request headers. It's designed to work exclusively in Server Components because it accesses server-side request data that isn't available in the client-side JavaScript bundle.
- How do I fix "headers() can only be called in a Server Component"?
- This error occurs when attempting to use Next.js's headers() function inside a Client Component. The headers() function is a server-only API that reads incoming HTTP request headers and can only be called in Server Components.
- What causes "headers() can only be called in a Server Component"?
- Directly calling headers() function inside a component marked with "use client" directive Importing a shared utility function or module that internally uses next/headers into a Client Component Converting a Server Component to Client Component without removing headers() calls
- Is the "headers() can only be called in a Server Component" error serious?
- It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- 📚React Official Documentation
- 📖Next.js Official Docs: headers() Function API Reference(Official Docs)
- 🐙
- 📖Next.js Official Docs: Server and Client Components(Official Docs)
- 🐙