This error occurs when you try to directly import a client component into a server component in Next.js App Router. The "use client" directive creates a module boundary between server and client code, preventing server components from directly importing client modules.
The "use client" directive in Next.js defines a boundary between server and client code on the module dependency tree, not the render tree. When you add "use client" to a file, you are telling Next.js that this module and everything it imports should be part of the client bundle and executed in the browser. The error occurs because server components cannot directly import client components. This is a fundamental architectural constraint in React Server Components - server-side code cannot reference client-side modules during the import phase. Any component imported by a client component must also be treated as a client component, creating a module dependency chain. However, it is important to understand that while you cannot import client components into server components, you can still render client components within server components by passing them as props (typically as children). This distinction between the module dependency tree and the component render tree is crucial to understanding how server and client components interact.
Review your components to determine which ones actually need client-side functionality (useState, useEffect, event handlers, browser APIs). Only these components should have the "use client" directive.
// This needs "use client" - uses useState
"use client";
import { useState } from "react";
export function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
// This does NOT need "use client" - just renders content
export function Header({ title }: { title: string }) {
return <h1>{title}</h1>;
}Separate client and server components into different files based on their requirements.
Instead of importing client components into server components, pass them as props (usually as children). This allows server components to compose client components without creating a module dependency.
// app/page.tsx (Server Component)
import { ServerDataComponent } from "./server-data";
// DO NOT import client component directly here
export default async function Page() {
const data = await fetchServerData();
return (
<div>
<ServerDataComponent data={data} />
{/* Client component will be passed as children */}
</div>
);
}
// app/layout.tsx (Server Component)
import { ClientInteractiveWidget } from "./client-widget";
import { MainContent } from "./main-content";
export default function Layout() {
return (
<MainContent>
<ClientInteractiveWidget />
</MainContent>
);
}The parent component (often a layout or page) handles the composition, not direct imports.
If you need to use a third-party component that requires client-side features, wrap it in your own client component file.
// components/chart-wrapper.tsx
"use client";
import { Chart } from "third-party-chart-library";
export function ChartWrapper({ data }: { data: any[] }) {
return <Chart data={data} />;
}Then import and use the wrapper in your server component:
// app/dashboard/page.tsx (Server Component)
import { ChartWrapper } from "@/components/chart-wrapper";
export default async function DashboardPage() {
const analyticsData = await fetchAnalytics();
return (
<div>
<h1>Dashboard</h1>
<ChartWrapper data={analyticsData} />
</div>
);
}This pattern isolates client-side dependencies from your server components.
If you have utility functions or constants in a file with "use client", move the server-safe code to a separate file without the directive.
// utils/constants.ts (NO "use client")
export const API_ENDPOINT = "https://api.example.com";
export const MAX_ITEMS = 100;
// utils/format.ts (NO "use client")
export function formatDate(date: Date): string {
return date.toISOString().split("T")[0];
}
// components/client-utils.ts (WITH "use client")
"use client";
export function useLocalStorage(key: string) {
// Client-only hook
}Now server components can safely import from utils/constants.ts and utils/format.ts.
Design your component architecture so server components handle data fetching and layout, while client components handle interactivity.
// app/products/page.tsx (Server Component)
import { ProductList } from "./product-list";
import { FilterSidebar } from "./filter-sidebar";
export default async function ProductsPage() {
const products = await fetchProducts();
return (
<div className="flex">
<FilterSidebar />
<ProductList initialProducts={products} />
</div>
);
}
// app/products/filter-sidebar.tsx (Client Component)
"use client";
import { useState } from "react";
export function FilterSidebar() {
const [filters, setFilters] = useState({});
// Client-side filtering logic
}
// app/products/product-list.tsx (Client Component)
"use client";
import { useState } from "react";
export function ProductList({ initialProducts }) {
const [products, setProducts] = useState(initialProducts);
// Client-side state management
}This architecture keeps concerns separated and prevents import errors.
Ensure the "use client" directive is placed at the very top of the file, before any imports.
// CORRECT
"use client";
import { useState } from "react";
import { Button } from "./button";
export function MyComponent() {
// component code
}// WRONG - directive after imports
import { useState } from "react";
"use client";
export function MyComponent() {
// This will cause errors
}The directive must be the first line (after any comments) for Next.js to properly identify the client boundary.
Install and use the server-only package to explicitly mark server-only code and get build-time errors if accidentally imported into client components.
npm install server-only// lib/server-utils.ts
import "server-only";
export async function getSecretData() {
// This function can only be used in server components
const secret = process.env.SECRET_KEY;
return fetchDataWithSecret(secret);
}If you try to import this into a client component, you will get a clear error at build time. Similarly, use client-only package for client-specific code.
Understanding the module dependency tree versus the render tree is critical for working with React Server Components. The "use client" directive affects how Next.js bundles and splits your code, not just where components render. When you mark a file with "use client", that file and all its imports become part of the client JavaScript bundle sent to the browser.
For large applications, carefully consider component boundaries to minimize client bundle size. Every import in a client component file adds to the bundle, so keep client components focused and small. Use dynamic imports with next/dynamic for heavy client components that are not immediately needed.
The composition pattern (passing components as props/children) works because the server component is not directly importing or calling the client component - it is just passing JSX that was created elsewhere. The parent component orchestrates the composition, keeping the module boundaries clean.
In monorepo setups or when working with shared component libraries, establish clear conventions about which packages contain client components versus server components. Consider using package-level "use client" declarations or organizing packages by environment.
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