Gabriel Neuman
Gabriel Neuman
💡 Aprendizaje29 de abril de 2026·modoFundraising·Gabriel Neuman

El prefetch de Next.js que cerraba sesión solo

Un Link de Next.js apuntando a la ruta de logout hacía que el prefetch automático en producción cerrara la sesión apenas cargaba el sidebar.

💡 Aprendizaje clave

En Next.js producción, <Link> prefetchea cualquier href automáticamente — incluso rutas API que tienen efectos secundarios. Nunca uses Link para logout.

#next-js#debugging#cookies#vercel#claude-code

Resumen del día

Día de debugging intenso en modoFundraising. El panel admin funcionaba perfecto en local pero en Vercel nadie podía quedarse logueado — cada vez que cargaba el dashboard, la sesión se cerraba sola. El bug vivía en un <Link> apuntando a /api/auth/logout en el sidebar.

Por proyecto

modoFundraising

El síntoma era claro: 401 en todos los endpoints de admin en producción. En local, todo andaba. Se descartó JWT, cookies, env vars — todo estaba bien.

El diagnóstico fue con browse headless (Chromium automatizado):

  1. Se hizo login → POST /api/auth/login → 200 ✓
  2. Se cargó /admin/dashboard → 200 ✓
  3. Inmediatamente: GET /api/auth/logout?_rsc=1r66z → 307 ← el asesino
  4. Redirect a /auth/login — sesión destruida

El ?_rsc=1r66z es la firma de un prefetch de React Server Components. El sidebar tenía esto:

// MALO — Next.js prefetchea esto en producción
<Link href="/api/auth/logout">
  Cerrar sesión
</Link>

En producción, Next.js prefetchea todos los <Link> visibles al cargar la página. Al prefetchear /api/auth/logout, ejecuta la ruta real → borra la cookie → sesión muerta. En desarrollo esto no pasa porque el prefetch está deshabilitado.

Fix:

// CORRECTO — solo navega cuando el usuario lo clickea
<button onClick={() => { window.location.href = "/api/auth/logout"; }}>
  Cerrar sesión
</button>

Aplicado en src/components/admin/sidebar.tsx y src/components/portal/sidebar.tsx.

Aprendizaje clave

<Link> en Next.js no es un anchor HTML — es un prefetcher. En producción, cualquier ruta que tengas en un <Link> se va a ejecutar silenciosamente cuando el usuario cargue la página que contiene ese link. Si esa ruta tiene efectos secundarios (logout, envío de emails, mutaciones), se van a disparar sin que nadie clickee nada.

Regla: para cualquier acción con efecto secundario (logout, delete, submit), usar <button> o <a> nativo, nunca <Link>.

El bug era imposible de reproducir en local porque el prefetch de Next.js está deshabilitado en development mode. Solo vivía en producción (Vercel).

Pendientes para mañana

  • Verificar que el deploy en Vercel resuelve el 401 en postulaciones
  • Confirmar que correos de admisión/rechazo vuelven a funcionar
  • Confirmar que el calendario vuelve a sincronizar asistentes