La solución para los errores de App Router generados por IA es una defensa de tres capas: reglas en CLAUDE.md para prevenir los 7 errores más comunes, AGENTS.md para fundamentar a Claude en docs precisos por versión, y next-devtools-mcp para feedback de errores en tiempo real.
Cuando combinas Claude Code con Next.js 16 (App Router), ciertos errores aparecen una y otra vez — "use client" en archivos de página, llamadas a Route Handlers desde Server Components, cookies() síncronos que funcionaban en Next.js 15 pero se rompieron en 16. La defensa de tres capas que describo aquí reduce esos errores a casi cero.
Este artículo cubre los 7 errores más comunes, cómo prevenirlos con CLAUDE.md, y cómo next-devtools-mcp crea un ciclo de feedback de errores en tiempo real.
Por Qué Claude Code Se Equivoca con App Router
El problema central es simple: los datos de entrenamiento de Claude contienen mucho más código de Pages Router que de App Router. Pages Router fue el estándar durante 7 años (2016–2023). App Router se estabilizó en Next.js 13.4 (mayo 2023) — apenas hace 3 años.
Esto significa que el "instinto predeterminado" de Claude Code se inclina hacia patrones como:
getServerSidePropsen lugar de Server Components asíncronosuseRouterdenext/routeren lugar denext/navigation- Route Handlers para todo en lugar de Server Actions para mutaciones
useEffectpara obtención de datos en lugar de acceso directo en Server Components
CLAUDE.md ayuda, pero no es suficiente por sí solo. Claude puede seguir tus reglas al inicio de la sesión y gradualmente volver a patrones antiguos a medida que el contexto se llena.
La solución real es una defensa de tres capas:
- CLAUDE.md — reglas explícitas que Claude lee al inicio de sesión
- AGENTS.md — dirige a Claude a los docs de Next.js incluidos en
node_modulespara referencia precisa por versión - next-devtools-mcp — alimenta errores de build y errores de tipo a Claude en tiempo real
Los 7 Errores Más Comunes de Next.js Generados por IA
Estos provienen del blog oficial de Vercel, reportes de la comunidad y tres meses de desarrollo diario con Claude Code + Next.js en 32blog.
1. Llamar Route Handlers desde Server Components
// MAL — viaje de red innecesario
// app/users/page.tsx (Server Component)
export default async function UsersPage() {
const res = await fetch("http://localhost:3000/api/users");
const users = await res.json();
return <UserList users={users} />;
}
// BIEN — acceso directo a la base de datos en Server Component
// app/users/page.tsx (Server Component)
import { db } from "@/lib/db";
export default async function UsersPage() {
const users = await db.user.findMany();
return <UserList users={users} />;
}
Los Server Components se ejecutan en el servidor. Pueden acceder a bases de datos, sistemas de archivos y APIs internas directamente. Llamar a tu propio Route Handler crea una solicitud HTTP innecesaria a ti mismo.
2. Uso excesivo de "use client"
// MAL — toda la página se convierte en Client Component
"use client";
export default function DashboardPage() {
// Todo aquí se envía al navegador
}
// BIEN — solo el componente interactivo es Client Component
// app/dashboard/page.tsx (Server Component — sin directiva)
import { InteractiveChart } from "./interactive-chart";
export default async function DashboardPage() {
const data = await fetchDashboardData();
return (
<div>
<h1>Dashboard</h1>
<StaticSummary data={data} />
<InteractiveChart data={data} />
</div>
);
}
"use client" solo debe aparecer en los componentes hoja interactivos más pequeños. Claude tiende a agregarlo a archivos de nivel de página ante la primera señal de interactividad.
3. Ubicación incorrecta de Suspense Boundary
// MAL — Suspense envuelve el componente equivocado
export default function Page() {
return <AsyncDataComponent />;
}
async function AsyncDataComponent() {
const data = await fetchData();
return (
<Suspense fallback={<Loading />}>
<DataView data={data} />
</Suspense>
);
}
// BIEN — Suspense envuelve el componente asíncrono desde AFUERA
export default function Page() {
return (
<Suspense fallback={<Loading />}>
<AsyncDataComponent />
</Suspense>
);
}
async function AsyncDataComponent() {
const data = await fetchData();
return <DataView data={data} />;
}
Suspense debe envolver el componente que desencadena la operación asíncrona, desde el nivel padre. Colocarlo dentro del componente asíncrono anula su propósito.
4. Metadata en Client Components
// MAL — el export de metadata se ignora en Client Components
"use client";
export const metadata = { title: "Dashboard" };
// BIEN — metadata debe estar en un Server Component (page.tsx o layout.tsx)
// app/dashboard/page.tsx (sin "use client")
export const metadata = { title: "Dashboard" };
El export metadata solo funciona en Server Components. Si Claude agrega "use client" a un archivo de página, metadata deja de funcionar silenciosamente sin mensaje de error.
5. Falta de revalidation en Server Actions
// MAL — la UI no se actualiza después de la mutación
"use server";
export async function createPost(formData: FormData) {
await db.post.create({ data: { title: formData.get("title") as string } });
// La UI muestra datos obsoletos
}
// BIEN — revalidar la ruta afectada
"use server";
import { revalidatePath } from "next/cache";
export async function createPost(formData: FormData) {
await db.post.create({ data: { title: formData.get("title") as string } });
revalidatePath("/posts");
}
6. Usar redirect() dentro de try/catch
// MAL — redirect lanza internamente, es capturado por try/catch
"use server";
export async function loginAction(formData: FormData) {
try {
await authenticate(formData);
redirect("/dashboard"); // Esto lanza NEXT_REDIRECT, capturado abajo
} catch (error) {
return { error: "Login failed" }; // El redirect nunca ocurre
}
}
// BIEN — redirect fuera de try/catch
"use server";
export async function loginAction(formData: FormData) {
let success = false;
try {
await authenticate(formData);
success = true;
} catch (error) {
return { error: "Login failed" };
}
if (success) redirect("/dashboard");
}
redirect() funciona lanzando un error especial NEXT_REDIRECT. Si está dentro de try/catch, el redirect es absorbido.
7. Acceso síncrono a Request APIs (Next.js 16)
// MAL — acceso síncrono eliminado en Next.js 16
import { cookies } from "next/headers";
export default function Page() {
const cookieStore = cookies(); // Error de build en Next.js 16
}
// BIEN — acceso asíncrono requerido
import { cookies } from "next/headers";
export default async function Page() {
const cookieStore = await cookies();
}
Next.js 16 eliminó completamente el acceso síncrono a cookies(), headers(), params y searchParams. En Next.js 15 estos estaban deprecados con advertencias; en 16 lanzan errores de build. Claude frecuentemente genera la versión síncrona a partir de datos de entrenamiento antiguos.
Este es un punto de dolor común al migrar de Next.js 15 a 16. El codemod (npx @next/codemod@latest next-async-request-api .) maneja la mayoría de los casos, pero Claude sigue regenerando el patrón síncrono hasta que agregas la regla explícita en CLAUDE.md.
Configuración de CLAUDE.md para Proyectos Next.js
Aquí hay un CLAUDE.md práctico que previene los errores anteriores. Para una inmersión profunda en patrones de diseño de CLAUDE.md, consulta "Gestión de Contexto en Claude Code: Patrones de Diseño para CLAUDE.md."
# Project: Next.js 16 App Router
## Tech Stack
- Next.js 16.1 + TypeScript strict + Tailwind CSS v4
- App Router only. No Pages Router patterns
- React Server Components by default
## Critical Rules
- NEVER add "use client" to page.tsx or layout.tsx unless the entire page must be interactive
- NEVER call Route Handlers from Server Components — access data directly
- ALWAYS use async/await for cookies(), headers(), params, searchParams
- ALWAYS place Suspense boundaries OUTSIDE the async component
- ALWAYS call revalidatePath() or revalidateTag() in Server Actions after mutations
- NEVER put redirect() inside try/catch blocks
## Data Fetching
- Server Components: direct database/API access (no fetch to own Route Handlers)
- Client Components: Server Actions for mutations, Route Handlers only for third-party webhooks
- Cache: use the "use cache" directive for explicit caching
## Reference
- Read AGENTS.md for bundled Next.js docs location
- When unsure about an API, check node_modules/next/dist/docs/ first
AGENTS.md y Docs Incluidos
A partir de Next.js 16.2, la documentación completa de Next.js se incluye como archivos Markdown en node_modules/next/dist/docs/. El AGENTS.md generado automáticamente le indica a las herramientas de IA que consulten estos docs antes de generar código. Para versiones anteriores, puedes generarlos con npx @next/codemod@latest agents-md.
Esta es la forma más efectiva de prevenir errores de "patrones antiguos." En lugar de depender de la memoria de Claude sobre las APIs de Next.js, lee los docs reales de la versión que tienes instalada. Las pruebas internas de Vercel mostraron una tasa de aprobación del 100% en evaluaciones de Next.js con docs incluidos, comparado con 79% con recuperación bajo demanda.
next-devtools-mcp — El Puente de IA Integrado en Next.js 16
Next.js 16 incluye un endpoint /_next/mcp que expone el estado del servidor de desarrollo a herramientas de IA. El paquete next-devtools-mcp conecta Claude Code a este endpoint.
Configuración
Agrega a .mcp.json en la raíz de tu proyecto:
{
"mcpServers": {
"next-devtools": {
"command": "npx",
"args": ["-y", "next-devtools-mcp@latest"]
}
}
}
Luego inicia tu servidor de desarrollo (npm run dev) y Claude Code se conectará automáticamente.
Qué proporciona
| Herramienta | Qué hace |
|---|---|
get_errors | Retorna errores de build, errores de runtime y errores de tipo en tiempo real |
get_logs | Acceso a la salida de consola del servidor de desarrollo |
get_page_metadata | Estructura de rutas, tipos de componentes, modo de renderizado por página |
get_project_metadata | Configuración del proyecto, versión de Next.js, URL del servidor de desarrollo |
get_server_action_by_id | Localizar el archivo fuente de un Server Action específico |
Por qué esto importa
Sin MCP, el ciclo de feedback es: Claude escribe código → tú notas un error de build → lo pegas de vuelta → Claude lo arregla. Con next-devtools-mcp, Claude ve el error inmediatamente y puede auto-corregirse antes de que tú lo notes.
Esto es especialmente poderoso para el tipo de errores listados arriba. Una ubicación incorrecta de Suspense podría no lanzar un error visible pero aparecerá en get_page_metadata como comportamiento de renderizado inesperado.
Un Flujo de Trabajo Real con Claude Code × Next.js
Aquí está el flujo de trabajo que funciona para desarrollo diario de Next.js con Claude Code.
1. Configuración de sesión
# Iniciar servidor de desarrollo en segundo plano
npm run dev
# Iniciar Claude Code
claude
Claude Code se conecta a next-devtools-mcp automáticamente. Ejecuta /context para verificar que MCP está cargado. Si no conoces los comandos de Claude Code, consulta el "Cheatsheet de Comandos de Claude Code."
2. Ciclo de desarrollo de funcionalidades
- Describe la funcionalidad que quieres
- Claude genera código — CLAUDE.md previene los 7 errores comunes
- next-devtools-mcp retroalimenta cualquier error en tiempo real
- Claude se auto-corrige sin necesidad de que pegues errores
- Revisa el código generado para corrección lógica
3. Validación pre-commit
Usa un PostToolUse Hook para ejecutar automáticamente la verificación de tipos después de ediciones:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npx tsc --noEmit --pretty 2>&1 | head -20"
}
]
}
]
}
}
4. Gestión de contexto
/compactcuando trabajas en una funcionalidad por mucho tiempo/clearcuando cambias a una funcionalidad diferente- Session-handoff.md para trabajo multi-sesión
Para una inmersión profunda en estrategias de gestión de contexto, consulta "Por Qué Claude Code Olvida y Cómo Solucionarlo." Si tienes problemas con los límites de ventana de contexto, "Cómo Solucionar Context Window Exceeded en Claude Code" tiene soluciones específicas.
Preguntas Frecuentes
¿Claude Code funciona con Pages Router?
Sí, Claude Code funciona tanto con Pages Router como con App Router. Los problemas de este artículo son específicos de las convenciones de App Router. Si tu proyecto aún usa Pages Router, los defaults de Claude en realidad se alinean mejor porque los datos de entrenamiento contienen más patrones de Pages Router.
¿Necesito las tres capas (CLAUDE.md, AGENTS.md, MCP)?
Cada capa atrapa problemas diferentes. CLAUDE.md previene errores conocidos proactivamente. AGENTS.md asegura precisión de versión. MCP captura errores de runtime que Claude no puede predecir. Puedes empezar solo con CLAUDE.md y agregar las demás incrementalmente — pero en mi experiencia, el salto real en productividad llegó cuando las tres estaban activas.
¿next-devtools-mcp funciona con otras herramientas de codificación IA?
Sí. El endpoint /_next/mcp usa el Model Context Protocol abierto, así que cualquier herramienta compatible con MCP puede conectarse. Cursor, Windsurf y GitHub Copilot (con soporte MCP) pueden usar la misma configuración.
¿Cuánto cuesta next-devtools-mcp en tokens?
Las llamadas a herramientas MCP consumen tokens de contexto. En la práctica, get_errors retorna JSON compacto — típicamente 200–500 tokens por llamada. El costo en tokens es mucho menor que pegar errores de build manualmente. Monitorea el uso con /context y desconecta los servidores MCP que no necesites.
¿Las reglas de CLAUDE.md se ignoran cuando el contexto se llena?
Puede pasar. CLAUDE.md se carga al inicio de la sesión, y a medida que el contexto crece, las instrucciones iniciales pierden influencia. Por eso el enfoque de tres capas es importante — aunque las reglas de CLAUDE.md se diluyan, AGENTS.md y MCP funcionan como barreras independientes. Usa /compact regularmente para mantener el contexto ligero.
¿Puedo usar esta configuración con Next.js 15?
La mayoría de las reglas de CLAUDE.md aplican a Next.js 15, excepto el error #7 (APIs de Request asíncronas), que en 15 era solo una advertencia de deprecación. Los docs incluidos en node_modules/next/dist/docs/ son una feature de Next.js 16.2+, pero puedes generar AGENTS.md manualmente con el codemod de Next.js.
¿Cuál es la diferencia entre CLAUDE.md y AGENTS.md?
CLAUDE.md es específico de Claude Code — contiene reglas del proyecto, convenciones y restricciones que Claude lee al inicio de sesión. AGENTS.md es agnóstico de herramienta y le dice a cualquier herramienta de codificación IA dónde encontrar documentación de referencia. En proyectos Next.js, AGENTS.md apunta a los docs incluidos, mientras que CLAUDE.md define reglas de comportamiento como "nunca uses 'use client' en archivos de página."
Conclusión
Claude Code es notablemente capaz en desarrollo de Next.js — una vez que le das las barreras correctas.
| Capa | Qué hace | Esfuerzo de configuración |
|---|---|---|
| CLAUDE.md | Previene los 7 errores comunes de App Router | 5 minutos |
| AGENTS.md | Fundamenta a Claude en docs de Next.js precisos por versión | Automático con create-next-app |
| next-devtools-mcp | Ciclo de feedback de errores en tiempo real | 2 minutos |
| Hooks | Ejecuta verificaciones de tipo automáticamente después de ediciones | 5 minutos |
El patrón es simple: restringir con CLAUDE.md, fundamentar con docs incluidos, validar con MCP. Configura estas tres capas correctamente y Claude Code dejará de generar patrones de 2023 para tu codebase de 2026.
Artículos relacionados: