Next.js vs Express: solo uno de los dos renderiza
Express es un servidor sobre el que construyes. Next.js es un framework de renderizado con un servidor incorporado. Elegir entre ambos es elegir cuánto quieres escribir tú.
A estos dos se los compara porque los dos son Node y los dos sirven HTTP, que es más o menos donde acaba el parecido. Express es un framework HTTP mínimo que compones tú. Next.js es un framework de renderizado que además incluye un servidor.
La decisión no es realmente una comparación. Es una pregunta sobre qué estás construyendo.
Si estás construyendo una API y nada más
Usa Express, o Fastify, o Hono. Los route handlers de Next.js existen y funcionan, pero estarías asumiendo un framework de renderizado, un paso de build, un enrutador basado en sistema de archivos y una dependencia de React para un servicio que no renderiza nada.
En concreto, Express sigue siendo mejor cuando tu API tiene:
- Consumidores externos. Rutas versionadas, claves de API, contratos documentados.
- Su propia cadena de middleware. Límite de tasa, validación de peticiones, autenticación a medida, logging que es tuyo.
- Algo de larga duración. WebSockets, server-sent events, conexiones que sobreviven a una petición.
- Restricciones de despliegue. Un proceso Node simple es más fácil de operar sobre infraestructura con opiniones.
Si renderizas páginas, no lo construyas tú
La dirección contraria es más contundente y menos obvia.
Los equipos que empiezan con Express y añaden React encima acaban escribiendo a mano lo que Next.js ya decidió: enrutado, code splitting, obtención de datos en el servidor, streaming, la frontera del bundle de cliente, manejo de imágenes, caché. Cada uno es una semana. Juntos son un framework, y será uno peor, porque es un proyecto paralelo y no el producto.
Si tu aplicación tiene páginas, el argumento a favor de Express es el argumento a favor de escribir tu propio framework. Eso es correcto de vez en cuando y normalmente no.
Dónde los route handlers bastan de verdad
Para una API que solo consume tu propio front end, los route handlers de Next.js hacen el trabajo:
// app/api/products/route.ts
export async function GET(request: Request) {
const products = await db.product.findMany();
return Response.json(products);
}Un despliegue, una base de código, tipos compartidos entre la API y los componentes que la llaman. Para la mayoría de las aplicaciones de producto, esta es la cantidad correcta de maquinaria.
Conviene saberlo: para los datos que necesitan tus propias páginas, a menudo no hace falta una ruta. Un Server Component puede consultar directamente, y una Server Action puede mutar; el rodeo por tu propia API HTTP es una costumbre heredada de una arquitectura renderizada en el cliente.
El arreglo en el que acaban la mayoría de los equipos
Express - o Fastify, o un servicio en Go, o Laravel - sosteniendo la lógica de negocio y los trabajos. Next.js sosteniendo el front end. Hablan por HTTP.
Es la misma conclusión que en Next.js frente a Laravel, por la misma razón: el render path y la lógica de negocio son problemas distintos, y los frameworks son buenos en uno de ellos cada uno.
Lo que no hay que hacer
Un servidor Express personalizado delante de Next.js. Está soportado y desactiva la optimización estática automática en las rutas que sirve, que es casi todo aquello por lo que viniste. Si necesitas un proxy, ponlo delante de los dos procesos en lugar de dentro de uno.
Portar una cadena de middleware de Express a proxy.ts. La convención que
sustituyó a middleware en la 16 corre en Node,
no es configurable y se ejecuta en peticiones que
no tenías previstas. Es para decisiones de enrutado, no para un pipeline de
peticiones.
