---
title: "The Core Choices of ElysiaJS and Hono: Apples and Oranges? No, a Legendary Duo"
description: "If you write backends on serverless, you've almost certainly used Hono a lot, but it may not be your only answer. ElysiaJS smells delicious and is worth a taste..."
author: "kidneyweakx"
published: 2025-10-10T00:00:00.000Z
updated: 2026-10-29T11:23:42.393Z
lang: en
tags: ["serverless", "typescript", "elysia", "hono"]
canonical: https://kidneyweakx.com/blog/elysiajs-and-hono-core-choice?lang=en
alternate_zh_tw: https://kidneyweakx.com/blog/elysiajs-and-hono-core-choice.md
alternate_ja: https://kidneyweakx.com/blog/elysiajs-and-hono-core-choice.md?lang=ja
---

# The Core Choices of ElysiaJS and Hono: Apples and Oranges? No, a Legendary Duo

> If you write backends on serverless, you've almost certainly used Hono a lot, but it may not be your only answer. ElysiaJS smells delicious and is worth a taste.

I happen to be using both right now: Solid(ar)ity's backend is **Hono + zod-openapi**, and this blog's CMS is **Elysia**, both running on Cloudflare Workers. After living with them for a while, I've noticed the two frameworks look a lot alike, but their core trade-offs are completely different. This post isn't a benchmark shootout; it compares "**what each one treats as its top priority**."

<br />

## The one-sentence version

* **Hono: Web standards first.** Its core is just `Request` in, `Response` out, so it runs anywhere: Workers, Deno, Bun, Node
* **Elysia: types first.** Its core is wiring types all the way through, from schema to handler to frontend client, and Bun is its home turf

Both are fast and both are small. The difference is what each is willing to sacrifice for its priority.

## Hono: native on Workers

The most comfortable thing about using Hono on Workers: **bindings sit right on the context.**

```ts
app.get('/posts', async (c) => {
  const index = await c.env.R2.get('index.json')
  return c.json(await index?.json())
})
```

`c.env` is simply this request's env, no magic involved. Workers is designed around "bindings travel with the request," and Hono happens to be shaped exactly around that model, so it never fights the platform.

If you need strict validation, add `@hono/zod-openapi`: write the schema once, and you get validation and OpenAPI docs together. Solid(ar)ity's backend is meant for other people to integrate with, so having auto-generated API docs matters a lot, and that's why I picked it in the first place.

## Elysia: types all the way to the frontend

Elysia's selling point is end-to-end type safety. Write your schema with TypeBox, and the handler's parameters, its return values, and even the types for calling the API from the frontend with Eden are all inferred automatically. **Change one side, and the other side lights up red immediately.**

For small projects where you write both the frontend and backend yourself, this experience is genuinely great; full-stack heaven. This blog's admin panel is a Svelte frontend hitting the Elysia API in the same repo. Change a field, and TypeScript instantly tells you everywhere that hasn't caught up.

<br />

But putting Elysia on Workers takes two compromises:

**1. You have to turn off AOT**

To be fast, Elysia by default generates code dynamically at startup (AOT compile). But Workers forbids dynamic code like `new Function` / `eval`, so you must do:

```ts
new Elysia({ aot: false })
```

Leave out this line and it errors out the moment you deploy. With AOT off, Elysia on Workers isn't as fast as it is on Bun, but for an admin panel you won't notice at all.

**2. You have to pass env around yourself**

Elysia has nothing like `c.env`. My approach is to wrap env in `AsyncLocalStorage` at the Worker's `fetch` entry point:

```ts
export default {
  fetch(request, env) {
    return runWithEnv(env, () => app.handle(request))
  },
}
```

Then pull it out inside handlers with `useEnv()`. This requires enabling `nodejs_compat` to get `node:async_hooks`. It works, but it's an extra layer of my own invention, and **write enough glue like this and it becomes tomorrow's tech debt.** The lighter your backend, the fewer headaches you'll hit later when you need to upgrade for some patch.

## So how do you choose?

My own rule of thumb is simple:

| Scenario | Pick |
| --- | --- |
| Mainly runs on Workers / multiple runtimes | Hono |
| API for others to integrate with, needs OpenAPI docs | Hono + zod-openapi |
| You write both frontend and backend, same repo, mainly on Bun | Elysia |
| You care a lot about types when the frontend calls the API | Elysia + Eden |

<br />

When it comes down to it, **Hono is a framework that grew along the grain of the platform; Elysia is a framework that grew along the grain of developer experience.** On Workers, the one that follows the platform has far less friction; on Bun, Elysia's type experience is hard to beat.

If I were rewriting the blog's admin panel today, I'd probably pick Hono and get rid of the two pieces of glue, AOT and AsyncLocalStorage. But I don't regret picking Elysia back then either. That rush of the frontend and backend going red together is really satisfying when you're building small tools.
