Back

Consejos para Migrar una Aplicación Express a Hono

Consejos para Migrar una Aplicación Express a Hono

Si mantienes una API en Express y estás considerando migrar a Hono, lo primero que vale la pena entender es que esta no es una migración de buscar y reemplazar. Express está construido sobre el módulo http de Node y sus propios objetos req/res. Hono, en cambio, está construido sobre la Fetch API y los estándares web. Esa diferencia lo condiciona todo: el enrutamiento, el middleware, el manejo de solicitudes y las respuestas.

Esto es lo que necesitas saber antes de empezar.

Puntos Clave

  • Express y Hono se basan en fundamentos radicalmente distintos: el módulo http de Node frente a la Fetch API y los estándares web.
  • Hono reemplaza los objetos req y res separados de Express por un único objeto de contexto c, y los manejadores deben devolver una Response.
  • Las firmas del middleware difieren — Express usa (req, res, next) mientras que Hono usa (c, next) con un next() esperado mediante await.
  • El parseo del cuerpo ocurre directamente dentro de los manejadores de Hono, en lugar de hacerse mediante middleware global.
  • Una migración incremental, comenzando por rutas JSON sin estado, es mucho más segura que una reescritura completa.

Comprende Primero la Diferencia Arquitectónica

Express envuelve los objetos IncomingMessage y ServerResponse de Node. Cada objeto req y res es específico de Node. Hono, por contraste, trabaja con objetos estándar Request y Response — los mismos que usarías en un navegador o en un Cloudflare Worker.

Cuando ejecutas Hono sobre Node.js, utilizas el adaptador @hono/node-server, que actúa como puente. Pero el manejador en sí permanece agnóstico al runtime.

// Express
app.get('/users/:id', async (req, res) => {
  const user = await db.findById(req.params.id)
  res.json(user)
})

// Hono
app.get('/users/:id', async (c) => {
  const user = await db.findById(c.req.param('id'))
  return c.json(user)
})

La forma es similar, pero c (el objeto de contexto) reemplaza tanto a req como a res. Devuelves una Response en lugar de invocar métodos sobre res.

Migración de APIs de Node.js a Hono: Empieza por Rutas sin Estado

El lugar más seguro para empezar a portar aplicaciones Express a Hono son las rutas sin estado y exclusivamente JSON — sin acceso al sistema de archivos, sin streams específicos de Node, sin middleware de sesiones. Estas se traducen limpiamente.

Las rutas que dependen de APIs específicas de Node (req.socket, res.locals, res.sendFile) requieren más reflexión. Aíslalas primero para saber a qué te enfrentas antes de comprometerte con una migración completa.

Migración de Middleware en Hono: No Asumas Compatibilidad

El middleware de Express sigue el patrón (req, res, next). El middleware de Hono usa (c, next) y normalmente invoca await next(). No son intercambiables.

// Middleware de Express
app.use((req, res, next) => {
  req.startTime = Date.now()
  next()
})

// Equivalente en Hono
app.use(async (c, next) => {
  c.set('startTime', Date.now())
  await next()
})

Para los paquetes más comunes, Hono cuenta con equivalentes oficiales:

ExpressEquivalente en Hono
cors()hono/cors
helmet()hono/secure-headers
express.json()Integrado mediante c.req.json()
morganhono/logger o un middleware personalizado

Reescribe el middleware de manera intencional en lugar de intentar envolver el de Express — la abstracción rara vez se mantiene de forma limpia.

Manejo del Cuerpo de la Solicitud y de la Respuesta

En Express 5, el parseo del cuerpo sigue basándose en middleware. En Hono, parseas el cuerpo directamente en el manejador:

// Parseo del cuerpo en Hono
app.post('/items', async (c) => {
  const body = await c.req.json()
  return c.json({ received: body }, 201)
})

Las respuestas siempre se devuelven, nunca se mutan. No existe res.status(201).json(...) — en su lugar, pasas el estado como segundo argumento a c.json().

Manejo de Errores

Express usa un manejador de errores de cuatro argumentos (err, req, res, next). Hono utiliza app.onError:

app.onError((err, c) => {
  console.error(err)
  return c.json({ error: 'Internal Server Error' }, 500)
})

Migra de Forma Incremental, No Todo de Golpe

Una reescritura completa rara vez sale bien. Un mejor enfoque:

  1. Porta un grupo de rutas aislado a la vez.
  2. Ejecuta Hono junto a Express durante la transición.
  3. Reescribe el middleware de forma explícita — no lo envuelvas.
  4. Deja las dependencias específicas de Node (manejo de archivos, autenticación heredada) para el final.

Conclusión

Portar aplicaciones Express a Hono es sencillo una vez que aceptas que ambos frameworks descansan sobre fundamentos distintos. La sintaxis de enrutamiento es lo suficientemente familiar como para que la mayoría de las rutas se traduzcan en minutos. El verdadero trabajo está en el middleware y en cualquier elemento que toque directamente APIs específicas de Node. Aborda esos casos con cuidado, y la migración se vuelve manejable.

Preguntas Frecuentes

Sí. Un patrón común es colocar un proxy inverso o un pequeño punto de entrada en Node frente a ambos, enrutando rutas específicas a la aplicación Hono y dejando el resto en Express. Esto te permite migrar grupos de rutas uno a uno y revertir rápidamente si algo se rompe, en lugar de comprometerte con un único cambio arriesgado.

Hono se ejecuta en Node.js, Bun, Deno, Cloudflare Workers, AWS Lambda y varios otros runtimes. En Node, utilizas el adaptador @hono/node-server para conectar el modelo de la Fetch API con el módulo http de Node. El mismo código de manejador permanece portable entre runtimes, lo cual es una de las principales ventajas de Hono sobre Express.

En general, no. El middleware de Express depende de los objetos req y res de Node y del callback next, mientras que el middleware de Hono opera sobre un contexto al estilo Fetch. Existen algunos adaptadores comunitarios, pero suelen ser frágiles. El enfoque recomendado es reescribir el middleware contra la API de Hono, ya que la mayoría de las necesidades comunes ya cuentan con equivalentes oficiales o integrados.

Hono suele ser más rápido que Express, especialmente en enrutamiento y respuestas JSON, gracias a su router ligero y a su diseño basado en Fetch. Las ganancias reales dependen de tu carga de trabajo — las consultas a bases de datos y las llamadas externas suelen dominar. Considera el rendimiento como un efecto secundario útil de la migración, no como la razón principal, a menos que tus benchmarks muestren que la sobrecarga del enrutamiento es un cuello de botella real.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay