Category: Next.js

  • Errores comunes al migrar a React Server Components en producción

    Errores comunes al migrar a React Server Components en producción

    React Server Components en producción: errores que nadie te cuenta

    Tiempo estimado de lectura: 5 min

    • Fronteras claras: mezclar datos pesados del servidor con Client Components provoca serialización y payloads enormes.
    • No convertir todo a client: usar “use client” globalmente anula los beneficios de RSC y regresa a una SPA pesada.
    • Latencia y caching: llamadas secuenciales y caché agresiva generan TTFB alto y fugas de datos entre usuarios.
    • Audita dependencias: muchas librerías no están preparadas para ejecución en server; lazy-load o wrappers client son necesarios.

    Introducción

    React Server Components en producción: errores que nadie te cuenta. Lo digo sin rodeos: los tutoriales y demos no te preparan para operarlos en tráfico real. En ese salto es donde aparecen fugas de datos, payloads monstruosos y cuellos de botella invisibles que desarman la promesa de “menos JS, mejor rendimiento”.

    Este artículo enumera los fallos concretos que verás en proyectos reales, aporta soluciones técnicas y define cuándo NO migrar a RSC. Incluye referencias y enlaces oficiales para que puedas profundizar: Suspense y caching en Next.js.

    Resumen rápido (lectores con prisa)

    Qué es: Patrón que permite renderizar parte de la UI en el servidor y enviar un árbol serializado al cliente.

    Cuándo usarlo: cuando puedas controlar la frontera server/client, minimizar datos pasados al cliente y beneficiarte de menos JS inicial.

    Por qué importa: mejora rendimiento y seguridad si se adopta con disciplina en serialización, caché y orquestación de datos.

    Cómo funciona: Server Components pueden acceder a recursos de servidor; Client Components se hidratan en cliente y deben recibir solo datos mínimos.

    1. React Server Components en producción: la frontera que rompe todo

    El error raíz es conceptual: tratar la frontera server/client como una línea estética en lugar de una decisión arquitectónica. Un Server Component puede acceder a la BD y luego pasar objetos enormes como props a un Client Component. Eso obliga a React a serializar todo en el HTML/JSON de respuesta. Resultado: la reducción del bundle se convierte en megabytes de payload.

    Ejemplo típico (malo)

    • Server Component hace SELECT * FROM orders WHERE user_id = ? y pasa todos los registros a <OrdersTable use client />.
    • El navegador recibe un payload serializado de decenas de MB.

    Solución: procesar, paginar y resumir en el servidor. Pasa al cliente solo el minimum viable (IDs, count, primeros N items) y provee endpoints client-side para cargar la página de datos al interactuar.

    2. El pánico del “use client” y la regresión a SPA

    Cuando algo falla (proveedores, librerías de UI, hooks), el atajo más común es colocar "use client" en el layout. Eso convierte todo el árbol en Client Components y anula el beneficio de RSC: vuelves a una SPA grande, con mayor complejidad y sin reducción de JS.

    Patrón correcto:

    • Mantén providers y estado en componentes hoja que realmente necesitan interactividad.
    • Diseña la composición para que los Client Components reciban props mínimos y, si requieren datos pesados, llamen a endpoints específicos (fetch desde cliente) o utilicen streaming.

    3. Waterfalls invisibles: el backend secuencial que mata TTFB

    Código like-this en Server Component:

    const user = await getUser(id);
    const prefs = await getPrefs(user.configId);
    const orders = await getOrders(user.id);
    

    Eso es secuencial: suma latencias. Aunque ocurre en servidor, el usuario espera. Paraleleza con Promise.all cuando no hay dependencia, y usa Suspense para streaming progresivo cuando sí hay dependencias parciales.

    Patrón secuencial y solución

    • Identifica llamadas independientes y ejecútalas en paralelo.
    • Usa streaming y Suspense para mostrar partes de la vista cuando están listas.
    • Mide TTFB en staging bajo carga para detectar waterfalls invisibles.

    4. Caché agresiva = fuga de datos entre usuarios

    Next.js y otros frameworks aplican caching por defecto en render server. Si renderizas una ruta con datos privados y no marcas la petición como dinámica, puedes cachear la vista de un usuario y servirla a otro. Es real y está pasando en producción.

    Contramedidas:

    • Para datos privados usa { cache: 'no-store' } en fetch o llama a APIs que leen cookies()/headers() (esto fuerza render dinámico en Next.js).
    • Revisa la documentación de caché de Next.js: caching en Next.js.
    • Considera políticas CDN más conservadoras para rutas autenticadas.

    5. Integraciones de terceros que no están listas para server execution

    Muchas librerías npm asumen un entorno DOM. Al ejecutar en server, aparecen errores en build o comportamiento inesperado. Resultado: el equipo marca "use client" masivo y pierde las ventajas. Revisa dependencias: algunas requieren reemplazo o lazy-loading estricto.

    Táctica práctica:

    • Audita las dependencias con npm ls y pruebas de build en CI que marquen dónde fallan.
    • Si una librería solo se usa en un widget, envuélvela en un Client Component lazy-loaded.

    Cuándo NO usar React Server Components

    No migres a RSC si tu producto encaja en alguno de estos casos:

    • Aplicaciones offline-first o PWAs que deben funcionar sin servidor.
    • Interfaces de hiper-interactividad: editores gráficos, juegos, vídeo en tiempo real o UIs con WebSockets a alta frecuencia.
    • Bases de código legacy sin presupuesto de reescritura: migrar Redux heavy/class components = reescritura, no refactor.

    Checklist práctico antes de migrar a producción

    1. Delimita claramente boundaries: quién corre en server y qué mínima data pasa al cliente.
    2. Añade tests de integración que simulen carga y validen payloads.
    3. Forza políticas de cache por ruta (privada vs pública).
    4. Instrumenta logs de tamaño de respuesta y tokenización/serialización.
    5. Adopta streaming/Suspense para vistas complejas; usa Promise.all para llamadas paralelas.
    6. Audita dependencias y evita convertir el layout en client por comodidad.

    Conclusión: RSC exige disciplina, no solo adopción

    React Server Components entregan ventajas claras (menos JS inicial, mayor seguridad para secretos, mejor SEO). Pero funcionan en producción solo si el equipo re-aprende backend: serialización, caching, latencia y orquestación de datos. La migración exitosa no es técnica aislada; es un cambio de modelo mental: pasar de “componentes” a “árboles de dependencias de red”. Si no estás dispuesto a trazar fronteras con rigor, no migres: estarás complicando tu arquitectura sin ganar sus beneficios.

    FAQ

    ¿Qué es exactamente un React Server Component?

    Un React Server Component se renderiza en el servidor y puede acceder a recursos del backend. No se hidrata en el cliente como un Client Component y se envía serializado al navegador.

    ¿Cuándo debo evitar migrar a RSC?

    Evita migrar si necesitas soporte offline completo, tienes UIs de hiper-interactividad (editores, juegos, video en tiempo real) o una base de código legacy sin presupuesto para reescritura.

    ¿Cómo evito pasar payloads gigantes al cliente?

    No pases objetos completos como props. Resumir, paginar y enviar solo lo mínimo necesario (IDs, count, primeros N items). Usa endpoints client-side para cargar datos adicionales bajo demanda.

    ¿Qué problemas de caché debo vigilar en Next.js?

    Cuidado con el render estático por defecto: rutas con datos privados pueden quedar cacheadas. Para datos privados usa { cache: 'no-store' } en fetch o APIs que lean cookies()/headers() para forzar render dinámico.

    ¿Cómo detectar y arreglar waterfalls en Server Components?

    Mide TTFB en staging bajo carga, revisa llamadas secuenciales en Server Components y paraleliza con Promise.all cuando sea posible. Usa streaming y Suspense para render progresivo.

    ¿Qué hago con librerías que fallan en server?

    Audita dependencias con npm ls, añade pruebas de build en CI y envuelve las librerías problemáticas en Client Components lazy-loaded o busca alternativas compatibles con server execution.

  • Mejorando rendimiento y SEO al migrar de Angular a Next.js 16

    Mejorando rendimiento y SEO al migrar de Angular a Next.js 16

    De Angular a Next.js 16: lo que aprendí migrando un proyecto real

    Tiempo estimado de lectura: 4 min

    • Rendimiento y SEO fueron el motor: migramos por Core Web Vitals malos, TTFB lento y bundle que penalizaba conversión móvil.
    • Server-first cambia la mentalidad: Next.js 16 y React Server Components mueven carga y lógica al servidor, reduciendo JavaScript en cliente.
    • Menos boilerplate para mutaciones: Server Actions permiten llamar funciones server-side desde formularios sin endpoints REST intermedios.
    • Fricciones reales: cache, alcance de “use client” y observabilidad requieren disciplina adicional en producción.

    De Angular a Next.js 16: lo que aprendí migrando un proyecto real empezó como un problema de negocio: Core Web Vitals malos, TTFB lento y un bundle que penalizaba conversión móvil. La migración no fue una moda técnica; fue una necesidad para reducir fricción de usuario y mejorar SEO técnico. Esto marcó cada decisión técnica que tomamos.

    Resumen rápido (lectores con prisa)

    Qué es: Next.js 16 (App Router) usa React Server Components para renderizar HTML en servidor y enviar JavaScript mínimo al cliente.

    Cuándo usarlo: cuando SEO, Core Web Vitals o TTFB afectan métricas de negocio y necesitas ejecutar lógica sensible en servidor.

    Por qué importa: reduce bundle inicial, mejora TTFB y simplifica flujos de datos server-side.

    Cómo funciona (resumen): renderizado server-side con funciones asíncronas para fetch/ORM, Server Actions para llamadas server desde forms y control explícito de caché y revalidación.

    De Angular a Next.js 16: por qué no es solo “aprender otra sintaxis”

    Angular es un framework opinado para SPAs: inyección de dependencias, RxJS y templates declarativos. Next.js 16 (App Router) invierte ese paradigma con React Server Components (RSC): renderizado en servidor, HTML entregado al cliente y JavaScript mínimo para interactividad. Documentación oficial Next.js.

    La diferencia no es menor: pasas de pensar “qué corre en el cliente” a “qué debe correr en el servidor”. Ese cambio impacta performance, seguridad y la forma en que estructuras estado y dependencias.

    Tres lecciones técnicas que cambiaron nuestro código

    1) RxJS se queda fuera del camino principal

    En Angular, RxJS orquesta peticiones, eventos y sincronizaciones. Eso ofrece control fino (cancelaciones, operadores), pero añade complejidad de mantenimiento (unsubscribe, memory leaks).

    En Next.js 16, Server Components son funciones async: await fetch() o llamadas al ORM desde el servidor. La simplicidad reduce boilerplate y evita parpadeos de carga en el cliente. Ejemplo real: reemplazar múltiples subscriptions por una única llamada asíncrona en el server simplificó la lógica y redujo errores de sincronización.

    Nota práctica: para cancelaciones del lado del cliente hay que usar explícitamente AbortController; la ergonomía de RxJS no existe por defecto.

    2) La inyección de dependencias se reimagina

    El contenedor DI de Angular es una comodidad arquitectónica (services providedIn: 'root'). React/Next no tienen un DI integrado. Las alternativas que adoptamos:

    • Instancias únicas exportadas desde módulos ES6 (clientes DB, SDKs).
    • React Context solo para estado UI que vive en cliente (tema, sesión).
    • Props/Composición para inyección explícita en componentes que dependen de servicios.

    Resultado: más explicitud y trazabilidad, pero más disciplina para no propagar dependencias globales por accidente.

    3) Server Actions: menos endpoints, menos boilerplate

    Migrar formularios del flujo Angular (form → HttpClient → endpoint REST → backend) a Server Actions colapsó la cadena. En Next.js 16 puedes llamar funciones en el servidor directamente desde el form:

    export async function updateUser(formData: FormData) {
      'use server';
      const name = formData.get('name') as string;
      await db.user.update({ where: { id: session.userId }, data: { name } });
      revalidatePath('/profile');
    }

    El beneficio es claro: menos endpoints internos y menos código repetitivo. El riesgo: mezclar lógica de negocio en componentes si no separamos responsabilidades adecuadamente. Docs de Server Actions

    Fricciones reales que te van a doler en producción

    • Cache y freshness: Next.js App Router tiene capas de caché (memoization, data cache, route cache). Sin revalidate o cache: 'no-store' puedes servir datos obsoletos. Leer.
    • “use client” propagate cost: marcar un componente como cliente arrastra su subárbol y puede romper los beneficios del SSR si importas librerías pesadas.
    • Observabilidad de comportamiento: la frontera servidor/cliente exige testing más exhaustivo (end-to-end + integración server actions) y pipelines de CI que validen rendimiento.
    • Seguridad y surface area: Server Actions facilitan lógica server-side, pero exigen revisar permisos y sanitización con más rigor.

    Criterio práctico para Tech Leads: ¿vale la pena migrar?

    No migres por moda. Migra si:

    • Tu producto es público y SEO o Core Web Vitals impactan conversiones (ver métricas en web.dev/vitals).
    • El bundle inicial y TTFB están bloqueando métricas de negocio.
    • Necesitas ejecutar lógica sensible en servidor para reducir exposición o proteger IP.

    Mantén Angular si:

    • Es un dashboard interno con poca necesidad SEO.
    • El equipo domina RxJS y la arquitectura actual es sostenible.
    • El coste de migración supera el beneficio económico esperado.

    Conclusión

    La migración De Angular a Next.js 16: lo que aprendí migrando un proyecto real fue menos una reescritura técnica y más una reorganización de responsabilidades: qué corre en el servidor, cómo se inyectan dependencias y cómo se gestionan mutaciones. Next.js 16 ofrece ganancias reales en rendimiento y simplicidad operativa, pero exige disciplina (caché, límites use client, separación de responsabilidades). Si tu negocio lo justifica, la inversión devuelve rendimiento y una arquitectura más alineada con un futuro server-first. Si no, Angular sigue siendo una opción sólida y productiva.

    FAQ

    Respuesta: Migramos porque Core Web Vitals malos, TTFB lento y un bundle grande estaban afectando conversión móvil y SEO. La migración fue una decisión de negocio para reducir fricción de usuario y mejorar SEO técnico.

    Respuesta: No hay un reemplazo directo. En Next.js 16 se usa programación asíncrona en Server Components (await fetch(), llamadas al ORM) y, para cancelaciones cliente, AbortController. La lógica de orquestación que RxJS ofrecía suele simplificarse en el servidor o con patrones de composición en cliente.

    Respuesta: Server Actions son funciones que se ejecutan en el servidor y se pueden invocar desde formularios en el cliente. Reducen la necesidad de endpoints REST intermedios. Requieren separar responsabilidades para no mezclar lógica de negocio en componentes. Más detalles.

    Respuesta: Los riesgos principales son caché y freshness (servir datos obsoletos sin revalidate), el coste de marcar componentes como cliente que arrastran subárboles pesados y la necesidad de mayor observabilidad y testing para la frontera servidor/cliente.

    Respuesta: No conviene migrar si el proyecto es un dashboard interno con poca necesidad SEO, si el equipo domina la arquitectura actual o si el coste de migración supera el beneficio económico esperado.

    Respuesta: Usar instancias únicas exportadas desde módulos ES6 (clientes DB, SDKs), React Context para estado UI cliente y props/composición para inyección explícita en componentes. Esto aporta trazabilidad a costa de disciplina para evitar dependencias globales indeseadas.

  • Implementa autenticación sencilla en Next.js con NextAuth.js

    Implementa autenticación sencilla en Next.js con NextAuth.js

    NextAuth.js / Auth.js: deja de reinventar la autenticación

    Tiempo estimado de lectura: 6 min

    Ideas clave

    • NextAuth.js (y la evolución a Auth.js v5) evita errores comunes en sesiones, cookies y tokens.
    • Dos estrategias de sesiones: JWT (performance) vs sesiones en base de datos (revocación instantánea).
    • Evita gestionar credenciales si no dominas hashing, salting y políticas de seguridad.
    • Si usas Next.js 14+, técnica y pragmáticamente conviene empezar con Auth.js (v5).

    Tabla de contenidos

    ¿Cansado de perder semanas armando autenticación como si fuera magia negra? Eso se acaba aquí.
    NextAuth.js no es solo otra librería bonita. Es el pegamento que evita que tu aplicación se desangre en sesiones, cookies y tokens. Es la forma razonable de decir: “No voy a reinventar esto” y, aun así, tener control total.

    Resumen rápido (lectores con prisa)

    NextAuth.js es una solución de autenticación open source diseñada para Next.js y arquitecturas Serverless. Úsala para gestionar sesiones, providers OAuth y passwordless sin construir todo desde cero. Importa porque abstrae validación en peticiones y reduce errores de cookies/tokens. Funciona con JWT o sesiones en base de datos según tus necesidades de rendimiento y revocación.

    Qué es, en pocas palabras

    NextAuth.js es una solución de autenticación open source creada para Next.js. Funciona bien con Serverless, Edge y App Router. No pretende sustituir a un proveedor de identidad empresarial, pero te da una capa de seguridad sólida, lista para producción, sin pagar licencia.
    Es como poner una cerradura profesional en la puerta de tu app sin contratar a un cerrajero. Es segura por defecto. Y flexible cuando lo necesitas.

    Por qué importa en el mundo moderno (y no es marketing)

    Next.js con App Router difumina la línea entre servidor y cliente. Ahora puedes ejecutar lógica en el servidor sin servidor fijo. Eso complica cookies, tokens y el control de sesiones. Si lo haces mal, expones rutas, filtrás datos y te conviertes en el peor tipo de soporte: el que responde “está en producción, no puedo tocarlo”.
    NextAuth.js abstrae eso. Valida en el momento de la petición, ideal para funciones Serverless o runtimes Edge. No necesitas un proceso que viva todo el tiempo. Ahorras costes. Escalas mejor. Y, sobre todo, reduces la superficie de errores humanos.

    Características que realmente importan

    No voy a pintarte una lista vacía. Esto es lo importante:
    • Soporte multi-proveedor (OAuth): conecta Google, GitHub, Apple, Discord, lo que sea. No reinventes OAuth.
    • Magic Links (passwordless): menos fricción, menos contraseñas que filtrar.
    • Adapters para DB y ORMs: Prisma, Drizzle, Mongo, Supabase. Tú eliges dónde almacenarlos.
    • Seguridad por defecto: CSRF, firma de cookies, tokens cifrados (JWE) —activados sin tener que leer 200 páginas.
    • Edge-ready: puedes validar sesiones casi al instante si lo ejecutas cerca del usuario.
    No es perfecto, pero es un buen comienzo. Y un comienzo con sentido.

    El dilema clásico: manejar credenciales propias

    Puedes usar el proveedor de “credentials” y manejar usuarios/contraseñas tú mismo. Suena bien hasta que lees la letra pequeña: gestionar contraseñas implica responsabilidad. Hashing, salting, políticas, reset de contraseñas, protección frente a ataques por fuerza bruta.
    NextAuth.js permite credenciales, pero la recomendación oficial y práctica es evitarlo si no sabes exactamente lo que haces. Además, si usas ese proveedor, NextAuth.js fuerza sesiones en JWT y desactiva sesiones en BD. No es capricho: es una decisión para reducir malas prácticas.

    Arquitectura de sesiones: dos caminos y una decisión

    Aquí viene la parte que separa proyectos tranquilos de proyectos que arden. Hay dos estrategias principales:

    1) JWT (por defecto)

    La información viaja en la cookie, cifrada. Rápido. No consultas la DB en cada petición. Ideal para apps con mucho tráfico. Problema: invalidar sesiones inmediatamente es más complejo. Si quieres expulsar a alguien ya, el token sigue válido hasta que expire.

    2) Sesiones en base de datos

    La cookie guarda solo un ID. La verificación exige una consulta a la base de datos. Perfecto si necesitas cortar accesos en tiempo real (ej. revocar a un usuario). Coste: latencia adicional por cada validación.
    No hay una respuesta universal. Si tu app es una red social con millones de peticiones, JWT suele ser la opción. Si es un panel de control bancario donde cortar accesos rápido es crítico, la base de datos gana.

    La transición que incomoda: NextAuth.js v4 → Auth.js v5

    Esto tiene que quedar claro: el ecosistema está en movimiento. NextAuth.js está evolucionando hacia Auth.js (v5). ¿Por qué? Porque no quieren quedarse atados solo a Next.js. Quieren que funcione también en otros frameworks: SvelteKit, SolidStart, Express…
    ¿Qué implica esto para ti?
    • Nueva API unificada. Más poderosa, mejor integración con Server Actions y App Router.
    • Documentación en proceso. La v5 ha estado en beta y la documentación todavía se alinea.
    • Si arrancas un proyecto con Next.js 14 o superior: técnica y pragmáticamente, empieza con v5. Evitarás dolores de migración.
    Sí, duelen las beta-docs. Pero es mejor migrar ahora que rehacerlo todo después.

    Un ejemplo real y útil (sin poesía)

    Piensa en un componente servidor que solo debe ver el usuario autenticado. Con Auth.js/NextAuth puedes validar en el servidor antes de renderizar:
    import { auth } from "@/auth"
    import { redirect } from "next/navigation"
    
    export default async function Dashboard() {
      const session = await auth()
      if (!session) redirect("/login")
      return <h1>Panel seguro de {session.user.name}</h1>
    }
    Eso no es ciencia ficción. Es práctica común. Y evita que la UI se entere antes que el servidor. La seguridad no depende del cliente.

    El dev escéptico y su evolución

    Conozco al dev escéptico. Le encanta escribir autenticaciones a mano. Cree que es más “limpio”. Tres meses después, está leyendo logs a las 3 a.m. por un problema de sesiones. Cambió. Aprendió. No renunció a la personalización: NextAuth.js ofrece callbacks, eventos y handlers. Puedes seguir siendo “muy tuyo” sin pagar el precio de hacerlo todo desde cero.

    Cuando no deberías usar NextAuth.js

    No todo es para todos. Elige otra cosa si:
    • Necesitas SAML/SSO empresarial complejo con flujos B2B avanzados.
    • Quieres una consola de usuarios y control RBAC administrada por un tercero (Clerk, Auth0 lo hacen).
    • Tu equipo no quiere tocar la infraestructura de usuarios y prefiere externalizarlo.
    Si la respuesta es “no me complico la vida” y estás dispuesto a pagar por eso, un SaaS puede ser mejor.

    Migración y estrategia práctica

    Si ya tienes autenticación casera, ¿migrar? Hazlo por fases:
    • Analiza qué needs tienes: invalidación en tiempo real, multi-provider, passwordless.
    • Implementa NextAuth.js en modo JWT en staging. Observa.
    • Si necesitas revocar sesiones pronto, añade el adapter y cambia a sesiones en DB.
    • Aprovecha callbacks para mapear datos de usuario sin romper tus modelos.
    No es tan doloroso. Pero exige disciplina.

    Pequeñas trampas que nadie te cuenta

    • No uses credentials si no entiendes hashing y políticas de seguridad.
    • Validar en cliente es mala idea. Siempre valida en servidor.
    • Documentación: si empiezas con v5, sigue la docs oficiales y ejemplos; ignora tutoriales viejos de v4.
    • Cookies seguras: en producción siempre en https y withSameSite apropiado.

    Metáfora útil (porque la mente recuerda imágenes)

    NextAuth.js es el portero de tu club. No decide a quién gustas. Solo asegura que el que entra esté autorizado. El portero no es el dueño del club, pero conoce la lista, sabe cuándo pedir identificación y tiene la potestad de sacar a cualquiera que cause problemas.

    Urgencia realista

    Si estás empezando un proyecto con Next.js 14+:
    • Empieza con Auth.js (v5).
    • Si pospones, la migración será más cara dentro de 6-12 meses.
    • No por FOMO, sino por coherencia técnica.

    CTA simple y sin vueltas

    ¿Quieres un setup funcional en 10 minutos? Haz esto: instala next-auth o auth y sigue la guía oficial para tu provider preferido. ¿Quieres que te lo arme paso a paso? Respóndeme este mensaje y te doy una checklist práctica y un ejemplo listo para copiar y pegar.

    Esto no acaba aquí

    Autenticación es una zona de fricción constante. Cambian las APIs, aparecen runtimes Edge, el usuario espera menos fricción y más seguridad. NextAuth.js te da una base sólida. Pero ninguna herramienta es el final de tu trabajo. Es la primera línea del plan.
    Si quieres, la próxima entrega la dedicamos a:
    • Migración completa v4 → v5.
    • Ejemplos avanzados con adapters (Prisma, Supabase).
    • Estrategias para invalidación instantánea y refresh tokens.
    ¿Quieres que sigamos? Respóndeme. No es una promesa vacía: es la continuación que necesitas para no aprender las cosas a las malas.

    FAQ

    ¿Qué es NextAuth.js / Auth.js?

    NextAuth.js es una solución de autenticación open source creada para Next.js; Auth.js (v5) es la evolución que amplía soporte a otros frameworks. Proporcionan manejo de sesiones, providers OAuth, magic links y adapters para DB/ORMs.

    ¿Cuándo usar JWT vs sesiones en BD?

    Usa JWT si priorizas performance y quieres evitar consultas a la DB por petición. Usa sesiones en BD si necesitas revocar accesos en tiempo real y tener control inmediato sobre sesiones.

    ¿Puedo manejar credenciales con NextAuth.js?

    Sí, existe el proveedor de “credentials”, pero no es recomendado si no controlas hashing, salting, políticas y protección frente a fuerza bruta. Además, usar credentials suele forzar sesiones en JWT y desactivar sesiones en BD.

    ¿Auth.js v5 es estable para nuevos proyectos?

    La v5 ha estado en beta y la documentación aún se alinea. Sin embargo, si arrancas con Next.js 14+, técnica y pragmáticamente conviene empezar con v5 para evitar migraciones futuras.

    ¿Cómo validar sesiones en servidor con App Router?

    Puedes llamar a la utilidad de autenticación en componentes servidor antes de renderizar. Ejemplo: llamar a auth() y redirigir si no hay sesión para evitar exponer rutas desde el cliente.

    ¿Qué proveedores soporta?

    Soporta múltiples providers OAuth como Google, GitHub, Apple, Discord, además de magic links y adapters para Prisma, Drizzle, Mongo, Supabase, entre otros.

    ¿Qué debo evitar al implementar autenticación?

    No uses credenciales si no entiendes seguridad de contraseñas. No confíes en validación en cliente. Asegura cookies en producción (https, SameSite). Sigue la documentación actual de la versión que eliges y evita tutoriales desactualizados.
  • Enviar correos transaccionales con Resend en React y NestJS

    Enviar correos transaccionales con Resend en React y NestJS

    Cómo usar Resend en React y NestJS

    Tiempo estimado de lectura: 4 min

    • Mantén consistencia visual entre web y correo usando plantillas React Email.
    • Protege claves renderizando en el servidor (NestJS) y guardando API keys en variables de entorno.
    • Escala correctamente con colas (BullMQ/Redis) para evitar bloquear peticiones.

    Cómo usar Resend en React y NestJS para enviar correos transaccionales sin sangrar tiempo en HTML quebrado ni exponer claves. Esta guía práctica muestra plantillas en React, render en servidor (NestJS) y entrega con Resend.

    Resumen rápido (lectores con prisa)

    Qué es: patrón para generar y enviar emails transaccionales usando plantillas React Email, render en NestJS y entrega vía Resend.

    Cuándo usarlo: cuando quieres consistencia visual entre web y email y no exponer claves en frontend.

    Por qué importa: reduce deuda técnica, mejora DX y entregabilidad al separar render y envío.

    Cómo funciona: escribe plantillas React, renderízalas en servidor con @react-email/render y envía con la API de Resend; procesa con colas para escalar.

    Cómo usar Resend en React y NestJS: flujo y por qué importa

    No es solo “mandar un email”. Es:

    • mantener consistencia visual entre web y correo,
    • no exponer claves,
    • evitar render duplicado,
    • y escalar sin convertir cada registro en un bloqueo HTTP.

    La solución: escribir plantillas con React Email, renderizarlas en NestJS usando @react-email/render y llamar a Resend para la entrega. Docs oficiales: Resend, React Email, NestJS.

    1) Plantilla en React (React Email)

    Instala dependencias en tu monorepo o carpeta compartida:

    npm install @react-email/components @react-email/render
    npm install -D react @types/react

    Ejemplo mínimo: src/emails/WelcomeEmail.tsx

    import * as React from 'react';
    import { Html, Body, Container, Text, Button } from '@react-email/components';
    
    export function WelcomeEmail({ name, url }: { name: string; url: string }) {
      return (
          
            
              Hola, {name}
              Verifica tu cuenta para empezar a usar la plataforma.
              
            
          
        
      );
    }

    Ventaja: el componente es testable, reutilizable y legible. React Email genera HTML compatible con clientes antiguos.

    2) Render y envío en NestJS

    Instala el SDK de Resend:

    npm install resend

    email.service.ts (esqueleto)

    import { Injectable, Logger } from '@nestjs/common';
    import { ConfigService } from '@nestjs/config';
    import { Resend } from 'resend';
    import { render } from '@react-email/render';
    import { WelcomeEmail } from '../emails/WelcomeEmail';
    
    @Injectable()
    export class EmailService {
      private resend: Resend;
      private logger = new Logger(EmailService.name);
    
      constructor(private config: ConfigService) {
        this.resend = new Resend(this.config.get('RESEND_API_KEY'));
      }
    
      async sendWelcome(to: string, name: string, verificationUrl: string) {
        const html = render(WelcomeEmail({ name, url: verificationUrl }));
        const res = await this.resend.emails.send({
          from: 'TuApp <noreply@tu-dominio.com>',
          to: [to],
          subject: `Bienvenido ${name}`,
          html,
        });
        this.logger.log(`Enviado: ${res.data.id}`);
        return res;
      }
    }

    Puntos clave:

    • La API key vive en variables de entorno. Nunca en frontend.
    • render() convierte JSX a HTML listo para enviar.
    • Usa ConfigService para separar entornos.

    Referencia de la API de envío: Referencia de la API de envío

    3) No bloquees peticiones: usa colas

    Enviar emails sin cola = romper UX y escalar mal. Usa BullMQ/Redis:

    • BullMQ docs
    • Patrón: controlador crea job -> responde 202 -> worker procesa job (llama a EmailService)

    Beneficios:

    • reintentos automáticos,
    • backpressure controlada,
    • workers horizontales.

    4) Producción: dominios, entregabilidad y observabilidad

    Configura DKIM, SPF y DMARC. Resend te da valores concretos durante la verificación. Enlaces útiles:

    Ejemplo mínimo SPF/DKIM

    • TXT @ v=spf1 include:resend.com ~all
    • Registros DKIM proporcionados por Resend
    • TXT _dmarc “v=DMARC1; p=quarantine; rua=mailto:postmaster@tu-dominio.com”

    Añade headers o tags en los envíos para trazar campañas o templates. Resend Dashboard permite ver bounces, opens y eventos.

    5) Buenas prácticas y decisiones técnicas

    • Reutiliza componentes visuales entre web y email cuando tenga sentido. No todo componente de UI es apto para email: usa @react-email/components para compatibilidad.
    • Mantén plantillas en una carpeta compartida o paquete npm interno (monorepo).
    • En entornos dev, whitelistea destinatarios para no spamear usuarios reales.
    • Telemetría: registra message-id, template tag y userId en logs para debug.
    • Si no usas React en tu stack, no añadas React Email solo por moda. El coste de la dependencia debe justificarse.

    Conclusión rápida

    Usar Resend en React y NestJS no es una moda: es un patrón que reduce deuda, mejora DX y facilita la entregabilidad. Resumen práctico:

    1. escribe plantillas con React Email;
    2. renderiza en NestJS con @react-email/render;
    3. envía con Resend y procesa con colas (BullMQ) en producción;
    4. verifica dominio y monitoriza.

    Si quieres, te dejo un ejemplo con BullMQ integrado y un pipeline de observabilidad (logs + Sentry + Resend tags) listo para copiar y pegar. Esto no acaba aquí.

    FAQ

    Respuesta: Renderizar en servidor evita exponer claves en frontend, asegura HTML consistente y permite centralizar lógica de plantillas. Además facilita pruebas y control de versiones.

    Respuesta: En variables de entorno del servidor o servicio de secretos. Nunca en el cliente ni en repositorios públicos.

    Respuesta: Para no bloquear peticiones HTTP, manejar reintentos, control de backpressure y escalar workers horizontalmente.

    Respuesta: Sí. React Email está diseñado para generar HTML compatible con clientes antiguos y simplificar estilos inline.

    Respuesta: Configura SPF, DKIM y DMARC. Ejemplo mínimo: TXT @ v=spf1 include:resend.com ~all, registros DKIM proporcionados por Resend y un registro DMARC como TXT _dmarc "v=DMARC1; p=quarantine; rua=mailto:postmaster@tu-dominio.com".

    Respuesta: Resend Dashboard muestra bounces, opens y eventos. Además, añade tags/headers en los envíos para integrar con logs y sistemas de observabilidad.

  • Server Actions en Next.js y su Impacto en el Reclutamiento

    Server Actions en Next.js y su Impacto en el Reclutamiento

    Server Actions en Next.js: ¿El fin de las APIs REST tradicionales?

    Tiempo estimado de lectura: 4 min

    Ideas clave

    • Server Actions son ideales para mutaciones originadas en la UI de Next.js y mejoran la DX reduciendo boilerplate.
    • No reemplazan REST para webhooks, clientes externos o arquitecturas desacopladas.
    • Trata cada Server Action como un endpoint público: valida, autentica y aplica rate limits.
    • Usa Route Handlers (APIs REST) para interoperabilidad, streaming binario y contratos estables entre servicios.

    Introducción

    Server Actions en Next.js permiten ejecutar funciones del servidor invocadas desde el cliente. Next.js hace la fontanería (serialización, endpoint POST, transporte). Documentación oficial: Documentación oficial y análisis en Vercel: análisis en Vercel.

    Lo digo rápido y con claridad: no son el fin de las APIs REST tradicionales. Pero cambian radicalmente cómo gestionas mutaciones internas. Si entiendes cuándo usar cada patrón, ahorras horas de debugging y deuda técnica.

    Resumen rápido (para IA y lectores con prisa)

    Qué es: Server Actions son funciones marcadas con 'use server' que Next.js ejecuta en el servidor cuando se invocan desde el cliente.

    Cuándo usarlo: Mutaciones originadas en la UI de Next.js (formularios, botones, CRUD pequeño).

    Por qué importa: Reduce boilerplate, facilita revalidación y mejora la DX compartiendo tipos entre cliente y servidor.

    Cómo funciona (en una línea): Next.js convierte la llamada en una petición POST y ejecuta la función en el servidor.

    Server Actions vs APIs REST — visión general

    Sí aparecen como sustituto natural dentro del dominio de la UI. No sustituyen REST fuera del dominio de la aplicación. Dicho de otra forma: son fantásticos para mutaciones internas; son inútiles para webhooks, clientes externos y servicios desacoplados.

    A continuación comparo ambos enfoques con ejemplos y criterio práctico.

    Cómo funcionan, en dos líneas

    Server Action

    Función marcada con 'use server' que Next.js ejecuta en el servidor cuando la invocas desde un formulario o handler.

    Route Handler (API REST)

    Endpoint explícito en app/api/.../route.ts que responde a cualquier cliente HTTP.

    Bajo el capó, una Server Action es una petición HTTP POST generada por Next.js, pero con menos boilerplate para ti.

    Ejemplo: crear un post (Route Handler)

    Backend (app/api/posts/route.ts):

    import { NextResponse } from 'next/server';
    import { db } from '@/lib/db';
    
    export async function POST(request: Request) {
      const body = await request.json();
      // validar con Zod aquí
      const post = await db.post.create({ data: body });
      return NextResponse.json(post, { status: 201 });
    }

    Frontend (cliente):

    'use client';
    async function handleSubmit(e: React.FormEvent) {
      e.preventDefault();
      const data = Object.fromEntries(new FormData(e.currentTarget));
      await fetch('/api/posts', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
      });
    }

    Control total sobre headers, status y streaming. Compatible con cualquier cliente (mobile, cron jobs, n8n).

    Ejemplo: crear un post (Server Action)

    Acción (app/actions.ts):

    'use server';
    import { db } from '@/lib/db';
    import { revalidatePath } from 'next/cache';
    
    export async function createPost(formData: FormData) {
      const title = String(formData.get('title') ?? '');
      const content = String(formData.get('content') ?? '');
      // validar y auth aquí
      await db.post.create({ data: { title, content } });
      revalidatePath('/posts');
    }

    Frontend:

    import { createPost } from '@/app/actions';
    
    export default function Form() {
      return (