Your agent wired a database query, a Redis call, or a file read into a page. The build now fails with Module not found pointing at a Node.js module such as fs, dns, or net. The import path is fine, the package is installed, and the same code ran when it lived in an API route.
The module is not missing. Server-only code ended up in the bundle that is built for the browser, and the browser has no fs.
Why this happens
The Next.js docs list this as one cause of the “Module not found” error: the module you are importing “uses Node.js specific modules, for example dns” in code that also runs in the browser. Their Redis example explains the chain: a library like ioredis depends on Node-only modules, so importing it into code that runs on both Node.js and the browser “will result in a module not found error for modules that ioredis relies on.”
In the App Router, the trigger is almost always the "use client" boundary. The docs say that once a file is marked "use client", “all of its imports and the components it directly renders are included in the client bundle.” An agent that adds "use client" to a page to make a button work has just pulled every import of that file, including your database helper, into the browser build.
How to tell if this is your problem
- Read the import trace in the build or dev error. It lists the chain of files that led to the failing module. Find the first file in the chain that starts with
"use client". - Check what the failing module belongs to.
fs,dns,net, or a package likeioredis, a database driver, or an ORM client means server code. - Look for a recent
"use client"line the agent added at the top of a page or component that also imports fromlib/or adbfile.
The fix
Keep server code in Server Components and pass the result down as props. The docs’ own pattern is a Server Component page that fetches data and hands it to a small client component:
// app/[id]/page.tsx (Server Component, no directive)
import LikeButton from '@/app/ui/like-button'
import { getPost } from '@/lib/data'
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params
const post = await getPost(id)
return <LikeButton likes={post.likes} />
}
// app/ui/like-button.tsx
'use client'
export default function LikeButton({ likes }: { likes: number }) {
// interactivity only, no database imports
}
Two details from the docs matter here:
- Put
"use client"on the smallest interactive file, not on the whole page. The docs recommend marking only the interactive components so the rest stays on the server. - Props must be serializable. Pass plain data (strings, numbers, objects), not a database client.
For the old Pages Router, the docs say to move the code into getStaticProps or getServerSideProps, and warn that this tree shaking only runs on top-level pages, so it cannot be relied on in separate components. A file that holds Node-only code should not also export React components.
Make the build catch it next time
Add import 'server-only' at the top of every file that touches the database, files, or secrets. The docs say that if such a module is imported into a Client Component, “there will be a build-time error”, which is a clear message instead of a confusing missing-module one. Installing the server-only package is optional in Next.js, but you may want it if your lint rules flag extraneous dependencies.
This also protects secrets: the docs note that only variables prefixed NEXT_PUBLIC_ reach the client bundle and others are replaced with an empty string, so a server helper imported on the client fails quietly instead of leaking.
How to avoid this next time
Add a rule to your agent’s instructions: “Never import database, file system, or secret-reading code into a file marked use client. Fetch in a Server Component and pass plain props down. Start every server-only helper with import 'server-only'.” In review, check that every "use client" file imports only UI code.
Comments
Sign in to join the conversation.
No comments yet — be the first.