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.
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.
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()) ❌ InvalidThe 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.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite