{
  "id": "ai-puts-server-code-in-client-components",
  "type": "failures",
  "category": "failures",
  "locale": "es",
  "url": "/es/failures/ai-puts-server-code-in-client-components",
  "title": "Cómo evitar que la IA coloque código del servidor en componentes del cliente",
  "description": "Los agentes de IA filtran consultas a la base de datos, variables de entorno secretas y APIs de Node.js en componentes 'use client', exponiendo lógica del servidor al bundle del navegador.",
  "tools": [
    "Cursor",
    "Claude Code",
    "Codex",
    "Windsurf"
  ],
  "stack": [
    "Next.js",
    "TypeScript"
  ],
  "tags": [
    "nextjs",
    "security",
    "react"
  ],
  "difficulty": null,
  "updated": "2026-06-08",
  "markdown": "El agente añade una directiva `\"use client\"` a un componente que importa Prisma,\n`fs` o una variable de entorno secreta, lo que envía ese código al bundle del\nnavegador de cada visitante.\n\n## El síntoma\n\nUn componente marcado con `\"use client\"` realiza una llamada directa a la base de datos o lee\nun secreto de `process.env`.\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\nLa compilación puede tener éxito (Next.js agrupa la importación) pero la página lanza un\nerror en tiempo de ejecución en el navegador porque `@prisma/client` requiere APIs de Node.js.\n\n## Por qué ocurre\n\nEl agente ve que se necesitan datos dentro de un componente que también usa estado o\nefectos, y recurre a la capa de datos que conoce. No modela el\nlímite servidor/cliente ni sabe que los componentes `\"use client\"` no pueden importar\nmódulos exclusivos de Node.js.\n\n## Cómo detectarlo\n\n- `\"use client\"` al inicio de un archivo que también importa desde `@/lib/db`,\n  `prisma`, `fs`, `path` o `crypto`.\n- `process.env.DATABASE_URL` o cualquier variable `_SECRET_` leída dentro de un\n  archivo `\"use client\"`.\n- La salida de compilación contiene `Critical dependency: the request of a dependency is\n  an expression` o una advertencia de bundle de Prisma.\n- El paquete `server-only` está ausente del proyecto.\n\n## Cómo solucionarlo\n\nDividir en un componente padre del servidor que obtiene los datos y un componente hijo del cliente\nque maneja la interactividad.\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## Prompt de solución\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## Prueba\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```"
}