{
  "id": "ai-puts-server-code-in-client-components",
  "type": "failures",
  "category": "failures",
  "locale": "en",
  "url": "/failures/ai-puts-server-code-in-client-components",
  "title": "How to Fix AI Putting Server Code in Client Components",
  "description": "AI agents leak database queries, secret env vars, and Node.js APIs into 'use client' components, exposing server-only logic to the browser bundle.",
  "tools": [
    "Cursor",
    "Claude Code",
    "Codex",
    "Windsurf"
  ],
  "stack": [
    "Next.js",
    "TypeScript"
  ],
  "tags": [
    "nextjs",
    "security",
    "react"
  ],
  "difficulty": null,
  "updated": "2026-06-08",
  "markdown": "The agent adds a `\"use client\"` directive to a component that imports Prisma,\n`fs`, or a secret env var — which ships that code to every visitor's browser\nbundle.\n\n## The symptom\n\nA component marked `\"use client\"` performs a direct database call or reads a\n`process.env` secret.\n\n```tsx\n\"use client\";\nimport { db } from \"@/lib/db\"; // Prisma client — Node.js only\nimport { useState, useEffect } from \"react\";\n\nexport function UserCard({ id }: { id: string }) {\n  const [user, setUser] = useState(null);\n\n  useEffect(() => {\n    // db is a Node.js module — this will throw at runtime in the browser\n    db.user.findUnique({ where: { id } }).then(setUser);\n  }, [id]);\n\n  return <div>{user?.name}</div>;\n}\n```\n\nThe build may succeed (Next.js bundles the import) but the page throws a\nruntime error in the browser because `@prisma/client` requires Node.js APIs.\n\n## Why it happens\n\nThe agent sees that data is needed inside a component that also uses state or\neffects, and reaches for the data layer it knows. It does not model the\nserver/client boundary or know that `\"use client\"` components cannot import\nNode.js-only modules.\n\n## How to spot it\n\n- `\"use client\"` at the top of a file that also imports from `@/lib/db`,\n  `prisma`, `fs`, `path`, or `crypto`.\n- `process.env.DATABASE_URL` or any `_SECRET_` variable read inside a\n  `\"use client\"` file.\n- Build output contains `Critical dependency: the request of a dependency is\n  an expression` or a Prisma bundle warning.\n- `server-only` package is absent from the project.\n\n## How to fix it\n\nSplit into a Server Component parent that fetches, and a Client Component child\nthat handles interactivity.\n\n```tsx\n// app/users/[id]/page.tsx — Server Component (no directive)\nimport { db } from \"@/lib/db\";\nimport { UserCard } from \"./UserCard\";\n\nexport default async function UserPage({ params }: { params: { id: string } }) {\n  const user = await db.user.findUniqueOrThrow({ where: { id: params.id } });\n  // Serialize — pass plain data, not the Prisma object\n  return <UserCard name={user.name} email={user.email} />;\n}\n```\n\n```tsx\n// app/users/[id]/UserCard.tsx — Client Component\n\"use client\";\nimport { useState } from \"react\";\n\nexport function UserCard({ name, email }: { name: string; email: string }) {\n  const [expanded, setExpanded] = useState(false);\n  return (\n    <div>\n      <p>{name}</p>\n      {expanded && <p>{email}</p>}\n      <button onClick={() => setExpanded((v) => !v)}>Toggle</button>\n    </div>\n  );\n}\n```\n\n```txt\n[ ] Install \"server-only\" and import it at the top of every server-side lib file\n[ ] No db/prisma imports in \"use client\" files\n[ ] No process.env secrets read in \"use client\" files\n[ ] Server Component fetches data; Client Component receives plain props\n[ ] Use Server Actions (not useEffect+fetch) when a client interaction needs db access\n```\n\n## Fix Prompt\n\n```txt title=\"Fix Prompt\"\nThis \"use client\" component imports server-only modules (Prisma, fs, or secret\nenv vars). Refactor it: move all data fetching into an async Server Component\nparent, pass only serializable props to the client component, and keep \"use\nclient\" only on the part that needs browser APIs or React state. Add\n\"server-only\" to any shared lib files that must never reach the browser.\n```\n\n## Test\n\n```bash\n# List all \"use client\" files that also import known server-only packages\ngrep -rl '\"use client\"' app/ | xargs grep -l \"prisma\\|@/lib/db\\|\\\"fs\\\"\\|\\\"path\\\"\\|\\\"crypto\\\"\" && echo \"FAIL: server code in client component\" || echo \"OK\"\n```"
}