Guía técnica

Backends TypeScript modernos: Hono, ElysiaJS y lo que viene después de NestJS

Comparación honesta de Hono, ElysiaJS y NestJS desde la experiencia en producción. DX, rendimiento, middleware, ORMs, despliegue flexible y cuándo elegir cada uno.

29 de enero de 202616 min de lecturaEquipo de Ingeniería Oronts

Por qué dejamos de arrancar proyectos nuevos con NestJS

NestJS es un gran framework. Hemos construido sistemas empresariales con él (Vendure funciona sobre NestJS internamente, y nos encanta Vendure). Pero para nuevos servicios backend independientes, nos pasamos a Hono. No porque NestJS sea malo. Porque Hono encaja mejor con nuestra forma de trabajar hoy.

El cambio fue gradual. Empezamos un nuevo servicio API, consideramos NestJS y nos preguntamos: realmente necesitamos decoradores, módulos, providers y el contenedor de inyección de dependencias inspirado en Angular para una API de 15 endpoints? La respuesta fue no. Necesitábamos un framework HTTP rápido que corra en cualquier runtime, con buen soporte de TypeScript y sin imponer una arquitectura.

Hono cumplió con eso. Después probamos ElysiaJS sobre Bun para un servicio donde el rendimiento era crítico. Eso nos dio algo diferente. Este artículo es una comparación honesta desde la experiencia de alguien que ejecuta los tres en producción.

Para contexto más amplio sobre cómo abordamos la ingeniería de software, esa guía cubre nuestros principios. Para ver cómo estos frameworks encajan en arquitectura de comercio, consulta nuestra guía de producción con Vendure.

Los tres frameworks

CaracterísticaNestJSHonoElysiaJS
RuntimeNode.jsNode, Bun, Deno, Cloudflare Workers, Lambda, VercelBun (principalmente)
ArquitecturaOpinionada (módulos, controladores, providers)Mínima (rutas, middleware)Mínima (rutas, plugins)
Seguridad de tiposDecoradores + validación en runtimeBasada en middleware, manualValidación integrada (typebox)
Contenedor DIIntegrado (estilo Angular)Ninguno (trae el tuyo)Ninguno (plugins)
Tamaño del bundleGrande (~50MB node_modules)Diminuto (~14KB core)Pequeño (~2MB con Bun)
Cold startLento (2-5s en Lambda)Rápido (< 100ms en Lambda)Rápido (< 50ms en Bun)
Ecosistema de middlewareGrande (passport, class-validator, etc.)Creciente (auth, cors, jwt, etc.)Creciente (swagger, jwt, etc.)
Curva de aprendizajePronunciada (módulos, decoradores, DI, guards, pipes)Mínima (similar a Express)Mínima (similar a Express con validación)
Ideal paraApps empresariales grandes, plugins de VendureAPIs multi-runtime, edge functions, microserviciosAPIs de alto rendimiento nativas de Bun

Hono: el framework que corre en todas partes

Hono es un framework web construido para el edge. Corre en Node.js, Bun, Deno, Cloudflare Workers, AWS Lambda, Vercel Edge y Fastly. El mismo código se despliega en cualquier runtime sin cambios.

import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { jwt } from 'hono/jwt';
import { logger } from 'hono/logger';

const app = new Hono();

// Middleware
app.use('*', logger());
app.use('*', cors({ origin: ['https://app.example.com'] }));
app.use('/api/*', jwt({ secret: process.env.JWT_SECRET! }));

// Rutas
app.get('/api/products', async (c) => {
    const products = await productService.findAll();
    return c.json({ data: products });
});

app.get('/api/products/:id', async (c) => {
    const product = await productService.findById(c.req.param('id'));
    if (!product) return c.json({ error: 'Not found' }, 404);
    return c.json({ data: product });
});

app.post('/api/products', async (c) => {
    const body = await c.req.json();
    const product = await productService.create(body);
    return c.json({ data: product }, 201);
});

export default app;

Por qué nos gusta

Portabilidad entre runtimes. Desplegamos el mismo código de Hono en Lambda (API Gateway), Bun (contenedor) y Cloudflare Workers (edge). Sin cambios de código entre runtimes. Esta es la fortaleza única de Hono. Ningún otro framework puede hacer esto.

14KB de core. Los cold starts en Lambda están por debajo de 100ms. Los cold starts de NestJS van de 2 a 5 segundos. En despliegues serverless, esa diferencia es toda la experiencia de usuario.

Sin opiniones sobre la arquitectura. Hono te da routing, middleware y contexto. Tú decides cómo estructurar servicios, repositorios y lógica de negocio. Para APIs pequeñas o medianas (5-50 endpoints), esto es exactamente lo correcto. No necesitas un sistema de módulos para 20 rutas.

Integración con tRPC. Usamos Hono + tRPC para stacks que son solo TypeScript. Type safety de extremo a extremo desde el servidor al cliente sin GraphQL:

import { trpcServer } from '@hono/trpc-server';
import { appRouter } from './trpc/router';

app.use('/trpc/*', trpcServer({ router: appRouter }));

Dónde se queda corto

Sin DI integrado. Para aplicaciones grandes con más de 50 servicios y grafos de dependencias complejos, necesitas traer tu propio contenedor de DI (tsyringe, inversify) o conectar las dependencias manualmente. Esto está bien para servicios pequeños. Se vuelve tedioso para los grandes.

Ecosistema de middleware más pequeño. NestJS tiene passport, class-validator, class-transformer, swagger y cientos de paquetes comunitarios. El ecosistema de Hono está creciendo pero todavía no está al mismo nivel. Vas a escribir más middleware personalizado.

Sin convenciones para apps grandes. Los módulos de NestJS te dan una estructura que escala a más de 100 archivos. Hono no prescribe estructura. Para equipos con desarrolladores junior, la falta de convenciones puede llevar a codebases inconsistentes.

ElysiaJS: cuando el rendimiento en Bun importa

ElysiaJS está construido específicamente para Bun. Aprovecha las APIs nativas de Bun, los bindings FFI y el servidor HTTP optimizado para lograr un rendimiento que los frameworks de Node.js no pueden igualar.

import { Elysia, t } from 'elysia';
import { swagger } from '@elysiajs/swagger';
import { jwt } from '@elysiajs/jwt';

const app = new Elysia()
    .use(swagger())
    .use(jwt({ name: 'jwt', secret: process.env.JWT_SECRET! }))
    .get('/products', async () => {
        return productService.findAll();
    })
    .post('/products', async ({ body }) => {
        return productService.create(body);
    }, {
        body: t.Object({
            name: t.String(),
            price: t.Number({ minimum: 0 }),
            description: t.Optional(t.String()),
        }),
    })
    .listen(3000);

Por qué es interesante

Validación integrada con TypeBox. Los schemas se definen inline, generan documentación OpenAPI automáticamente. No necesitas una librería de validación aparte. Los tipos fluyen desde el schema al handler hasta la respuesta.

Rendimiento nativo de Bun. ElysiaJS sobre Bun maneja 2-3x más peticiones por segundo que Express sobre Node.js para APIs JSON simples. Para cargas de trabajo con poco cómputo y mucho I/O (la mayoría de APIs), la diferencia es menos dramática pero sigue siendo medible.

Inferencia de tipos de extremo a extremo. El tipo del body de la request se infiere del schema de TypeBox. El tipo de la respuesta se infiere del handler. El cliente puede usar Eden (el cliente tipo tRPC de ElysiaJS) para llamadas API con type safety.

Dónde se queda corto

Solo Bun. Si necesitas desplegar en Node.js, Lambda o Cloudflare Workers, ElysiaJS no es una opción. Bun está listo para producción pero no es universalmente soportado en todos los entornos de hosting.

Ecosistema más pequeño. La compatibilidad de paquetes de Bun es buena pero no llega al 100%. Algunos paquetes de Node.js usan addons nativos que Bun no soporta. Drivers de bases de datos, librerías de procesamiento de imágenes y algunos módulos nativos de criptografía pueden ser problemáticos.

Menos probado en batalla. Bun y ElysiaJS son más recientes. La comunidad es más pequeña. Cuando te encuentras con un caso borde, hay menos respuestas en Stack Overflow y menos personas que hayan resuelto el mismo problema.

Drizzle vs Prisma vs TypeORM: la realidad de los ORM

La elección del framework es la mitad de la decisión. La elección del ORM es la otra mitad.

CaracterísticaDrizzlePrismaTypeORM
Estilo de querySimilar a SQL (explícito)Client API (generado)Active Record o Data Mapper
Seguridad de tiposExcelente (inferido del schema)Excelente (cliente generado)Buena (decoradores)
MigracionesBasadas en SQL, control manualAuto-generadas, gestionadasAuto-generadas o manuales
RendimientoRápido (wrapper delgado sobre SQL)Bueno (query engine)Moderado (abstracción pesada)
SQL crudoFirst-class (template sql``)Posible pero incómodoPosible vía query builder
Edge/ServerlessFunciona (ligero)Necesita Prisma Accelerate para edgeDemasiado pesado para edge
Curva de aprendizajeBaja (si conoces SQL)Baja (la documentación de API es excelente)Media (decoradores, relaciones)
Tamaño del bundlePequeño (~500KB)Grande (~15MB con engine)Medio (~5MB)
Mejor conHono, ElysiaJSCualquier frameworkNestJS, Vendure

Nuestras elecciones de stack

Hono + Drizzle + tRPC: para nuevas APIs TypeScript. Ligero, rápido, type-safe de punta a punta. La sintaxis similar a SQL de Drizzle nos da control explícito sobre las queries sin la sobrecarga de abstracción de TypeORM o la sobrecarga del engine de Prisma.

// Drizzle: similar a SQL, explícito, type-safe
const products = await db
    .select()
    .from(productsTable)
    .where(and(
        eq(productsTable.tenantId, tenantId),
        eq(productsTable.status, 'active'),
        gt(productsTable.price, 1000),
    ))
    .orderBy(desc(productsTable.createdAt))
    .limit(20);

NestJS + TypeORM: para plugins de Vendure y aplicaciones empresariales grandes donde el sistema de módulos y el contenedor de DI justifican su peso. TypeORM se integra profundamente con NestJS y Vendure.

Prisma: cuando necesitamos migraciones auto-generadas y el equipo valora la documentación de Prisma y la experiencia de desarrollo por encima del control granular de queries.

Flexibilidad de despliegue

Aquí es donde la elección de framework tiene el mayor impacto práctico.

Destino de despliegueNestJSHonoElysiaJS
Docker/KubernetesFuncionaFuncionaFunciona (imagen Bun)
AWS LambdaCold starts lentos (2-5s)Rápido (< 100ms)No soportado
Cloudflare WorkersNo soportadoFunciona nativamenteNo soportado
Vercel EdgeNo soportadoFunciona nativamenteNo soportado
Deno DeployNo soportadoFunciona nativamenteNo soportado
VPS tradicionalFuncionaFuncionaFunciona (necesita Bun)
Bun nativoParcial (la mayoría de NestJS funciona en Bun)FuncionaNativo, optimizado

Si despliegas solo en contenedores, los tres funcionan bien. Si despliegas en serverless o edge, Hono es el único framework que te da todas las opciones. ElysiaJS es solo Bun. NestJS es solo Node (en la práctica).

Para ver cómo desplegamos servicios en infraestructura cloud incluyendo Kubernetes, Lambda y edge functions, esa página cubre nuestro enfoque.

Cuándo NestJS sigue siendo la elección correcta

A pesar de nuestra preferencia por Hono en proyectos nuevos, NestJS es la elección correcta cuando:

  • Estás construyendo plugins de Vendure. Vendure ES NestJS. El sistema de plugins, los servicios, resolvers y guards usan patrones de NestJS. Pelear contra el framework es peor que usarlo.
  • Tu equipo conoce Angular. El patrón de módulos/providers/controladores de NestJS refleja Angular. Si tu equipo viene de Angular, la curva de aprendizaje es prácticamente cero.
  • Necesitas un ecosistema de middleware grande. Estrategias de Passport, class-validator, generación automática de Swagger, GraphQL code-first. NestJS tiene todo esto integrado o bien conectado.
  • La aplicación va a crecer a más de 100 archivos. Los módulos de NestJS proporcionan estructura que escala. Sin convenciones (Hono, ElysiaJS), equipos grandes necesitan disciplina para mantener la consistencia.
  • Necesitas soporte de WebSocket. NestJS tiene gateways de WebSocket integrados con el mismo patrón de decoradores. El soporte de WebSocket en Hono es más manual.

Errores comunes

  1. Elegir Hono y luego reconstruir NestJS. Si terminas añadiendo un contenedor de DI, routing basado en decoradores, sistema de módulos y patrón de guards a Hono, acabas de construir un NestJS peor. Usa NestJS.

  2. Elegir ElysiaJS para producción sin evaluar la compatibilidad de Bun. Verifica que todas tus dependencias funcionen en Bun. Addons nativos, drivers de bases de datos específicos y algunas librerías de criptografía pueden no funcionar.

  3. Ignorar los tiempos de cold start en serverless. NestJS en Lambda es inutilizable para APIs de cara al usuario sin provisioned concurrency. Hono en Lambda es suficientemente rápido sin eso.

  4. Usar TypeORM con Hono. TypeORM está diseñado para los patrones de DI de NestJS. Sin DI, gestionar las conexiones y repositorios de TypeORM es incómodo. Usa Drizzle o Prisma con Hono.

  5. Cambio de framework prematuro. Si tu app en NestJS funciona y tu equipo es productivo, no cambies a Hono solo por ser más moderno. Cambia cuando tengas una razón concreta (despliegue serverless, edge functions, nuevo servicio independiente).

  6. Sin capa de validación. Hono no incluye validación de requests. Usa middleware de Zod o construye el tuyo. Enviar una API sin validación de entrada es una vulnerabilidad de seguridad.

Conclusiones clave

  • Hono es el framework TypeScript backend más versátil. 14KB de core, corre en todos los runtimes, cold starts rápidos, sin opiniones sobre arquitectura. Nuestro default para nuevas APIs independientes.

  • ElysiaJS ofrece el mejor rendimiento en Bun. Validación integrada, gran DX, type-safe de extremo a extremo. Pero funcionar solo en Bun limita dónde puedes desplegarlo.

  • NestJS sigue siendo la elección correcta para apps empresariales grandes y Vendure. Módulos, DI, guards y un ecosistema masivo. La curva de aprendizaje se amortiza a escala.

  • Drizzle es nuestro ORM preferido con Hono. Sintaxis similar a SQL, queries explícitas, bundle ligero. Prisma para equipos que prefieren clientes auto-generados. TypeORM para NestJS/Vendure.

  • El destino de despliegue determina la elección de framework. Serverless y edge necesitan Hono. Contenedores funcionan con cualquiera. Bun nativo necesita ElysiaJS.

  • No cambies de framework sin una razón. Si NestJS te está funcionando, sigue usándolo. Cambia cuando necesites serverless, edge, o un nuevo servicio independiente donde el enfoque ligero sea genuinamente mejor.

Construimos backends TypeScript con los tres frameworks como parte de nuestra práctica de desarrollo web y software a medida. Si estás evaluando frameworks para un proyecto nuevo, habla con nuestro equipo o solicita un presupuesto.

Temas cubiertos

Hono frameworkElysiaJSTypeScript backendalternativa a NestJSBun backendDrizzle ORMNode.js modernoframework servidor TypeScript

¿Listo para construir sistemas de IA listos para producción?

Nuestro equipo se especializa en sistemas de IA listos para producción. Hablemos de cómo podemos ayudar.

Iniciar una conversación