This error occurs in Next.js when you try to directly import a Server Component into a Client Component marked with "use client". Client Components cannot import Server Components because any imported component becomes part of the client bundle and loses server-only capabilities.
In Next.js 13+ with the App Router, all components are Server Components by default unless marked with the "use client" directive. Server Components run only on the server and have access to server-only APIs like databases, file systems, and environment variables. Client Components run on both the server (for pre-rendering) and in the browser, supporting interactivity with hooks like useState and useEffect. When you import a component into a Client Component, that imported component is included in the client-side JavaScript bundle. This means it will run in the browser and must adhere to client-side constraints. If the imported component uses server-only features (like direct database queries or server-only packages), those will fail in the browser environment. Next.js prevents this by design: you cannot directly import Server Components into Client Components. Any component imported into a Client Component is automatically treated as a Client Component, and if it contains server-only code, you will get build-time or runtime errors.
The recommended pattern is to pass Server Components as children or props to Client Components, rather than importing them directly. This allows you to compose them without forcing them into the client bundle.
// ❌ WRONG: Directly importing Server Component into Client Component
"use client"
import ServerComponent from "./server-component"
export default function ClientComponent() {
return <div><ServerComponent /></div>
}
// ✅ CORRECT: Pass as children prop
// app/page.tsx (Server Component)
import ClientComponent from "./client-component"
import ServerComponent from "./server-component"
export default function Page() {
return (
<ClientComponent>
<ServerComponent />
</ClientComponent>
)
}
// app/client-component.tsx
"use client"
export default function ClientComponent({ children }: { children: React.ReactNode }) {
return <div className="wrapper">{children}</div>
}This pattern works because the Client Component receives the Server Component as an opaque prop - it does not need to know what is inside it.
If you have a component doing both server-side data fetching and client-side interactivity, split it into two components: one Server Component for data fetching and one Client Component for interactivity.
// ❌ WRONG: Mixed responsibilities
"use client"
import { useState } from "react"
import { db } from "@/lib/db"
export default function MixedComponent() {
const posts = await db.post.findMany() // Error! Cannot use db in Client Component
const [selected, setSelected] = useState(null)
// ...
}
// ✅ CORRECT: Split into Server + Client
// app/posts-page.tsx (Server Component)
import { db } from "@/lib/db"
import PostsList from "./posts-list"
export default async function PostsPage() {
const posts = await db.post.findMany()
return <PostsList posts={posts} />
}
// app/posts-list.tsx (Client Component)
"use client"
import { useState } from "react"
export default function PostsList({ posts }: { posts: Post[] }) {
const [selected, setSelected] = useState(null)
// Client-side interactivity only
}For server-side operations that need to be triggered from Client Components (like form submissions or data mutations), use Server Actions instead of trying to import Server Components.
// app/actions.ts (Server Action)
"use server"
import { db } from "@/lib/db"
export async function createPost(formData: FormData) {
const title = formData.get("title") as string
await db.post.create({ data: { title } })
}
// app/post-form.tsx (Client Component)
"use client"
import { createPost } from "./actions"
export default function PostForm() {
return (
<form action={createPost}>
<input name="title" />
<button type="submit">Create</button>
</form>
)
}Server Actions can be imported and called from Client Components safely because they are serialized and executed on the server.
Install and use the "server-only" package to explicitly mark modules that should never be imported into Client Components. This provides clear build-time errors.
npm install server-only// lib/database.ts
import "server-only"
import { PrismaClient } from "@prisma/client"
export const db = new PrismaClient()Now if someone tries to import this module into a Client Component, they will get a clear error message during build: "This module cannot be imported from a Client Component module."
For client-only code (like browser APIs), use the opposite package:
npm install client-onlyIf the component truly needs client-side interactivity and does not use server-only features, add "use client" at the top of the file.
// components/counter.tsx
"use client"
import { useState } from "react"
export default function Counter() {
const [count, setCount] = useState(0)
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
)
}Remember: "use client" must be at the very top of the file, before any imports. All components imported into this Client Component will also become Client Components.
Audit your component tree to understand which components are Server Components and which are Client Components. Draw a clear boundary.
// Example component hierarchy
app/page.tsx (Server Component)
├─ Header (Server Component)
├─ SearchBar (Client Component) ← "use client" boundary
│ └─ SearchIcon (Client Component - imported into Client)
├─ PostsList (Server Component)
│ ├─ PostCard (Server Component)
│ └─ LikeButton (Client Component) ← "use client" boundary
└─ Footer (Server Component)Once a component is marked "use client", all components it imports are also Client Components. Keep Client Components as small and focused as possible, with Server Components handling data fetching at the page or layout level.
Understanding the Server/Client boundary is critical for Next.js App Router development. Server Components are the default and should be your primary building block - they reduce JavaScript bundle size, allow direct database access, and improve performance. Only use Client Components when you need interactivity (useState, useEffect, event handlers) or browser APIs.
The composition pattern (passing Server Components as children to Client Components) works because React.ReactNode is serializable - the Client Component receives pre-rendered content without needing to know how it was generated. This is the same pattern used by React Context providers.
You can also pass Server Components as any prop name, not just children: <ClientComponent sidebar={<ServerSidebar />} />. The key is that the Client Component treats it as an opaque prop.
For third-party libraries that do not yet support Server Components, you may need to wrap them in your own Client Component with "use client" before using them. Many popular libraries are adding React Server Component support in 2024-2025.
Environment variables: NEXT_PUBLIC_* variables can be used in both Server and Client Components. Non-prefixed variables are only available in Server Components and will be undefined in Client Components, which is another reason to avoid mixing server logic into Client Components.
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