Hono vs ElysiaJS vs Nitro (2026)
Hono runs on Cloudflare Workers, Deno, Bun, Node.js, and AWS Lambda — the same code, no modifications. ElysiaJS is 2.3x faster than Hono on Bun benchmarks and provides end-to-end type safety without code generation. Nitro powers Nuxt.js and is designed as the universal server layer for modern JavaScript frameworks. These aren't competing for the same use case — they're designed for different contexts.
TL;DR
Hono for edge-first, multi-runtime APIs where portability is the priority. ElysiaJS for Bun-first applications where you want the fastest TypeScript backend with end-to-end type safety. Nitro when you're building a framework, server for a meta-framework (Nuxt, Analog), or need a universal server adapter layer. For most new JavaScript API projects in 2026, Hono is the pragmatic default.
Key Takeaways
- Hono: ~2M weekly npm downloads, 23K GitHub stars, runs on 9+ runtimes
- ElysiaJS: ~300K weekly downloads, 11K GitHub stars, Bun-first, fastest TypeScript framework
- Nitro: ~1.5M weekly downloads, 7K GitHub stars, Nuxt-backed, universal server layer
- Hono bundle: <14 kB, Web Standards-based (Fetch API, Request, Response)
- ElysiaJS Eden: end-to-end type safety without code generation (like tRPC but REST)
- Nitro: H3 routing + Rollup bundling + auto-imports + Cloudflare/Lambda adapters
- Express replacement context: all three are faster than Express
Why Not Express?
Express has 80M+ weekly downloads but was designed for Node.js in 2010. The issues in 2026:
- No native TypeScript support (community types are imperfect)
- Single-threaded, callback-based middleware
- No edge runtime support (uses Node.js APIs)
- No built-in type safety for request/response
These three frameworks are designed for the modern era: TypeScript-first, Web Standards-based, and edge-compatible.
Hono
Package: hono
Weekly downloads: 2M
GitHub stars: 23K
Creator: Yusuke Wada
Hono is built on Web Standards — it uses the Fetch API (Request/Response) as its core abstraction. This means the same Hono application runs on any JavaScript runtime that supports those standards.
Supported Runtimes
Cloudflare Workers ✓
Cloudflare Pages ✓
Deno Deploy ✓
Bun ✓
Vercel Edge ✓
AWS Lambda ✓
Node.js ✓
Fastly Compute ✓
Lagon ✓
Installation
npm install hono
Basic Usage
import { Hono } from 'hono';
const app = new Hono();
app.get('/', (c) => c.text('Hello World!'));
app.get('/json', (c) => c.json({ message: 'Hello', status: 'ok' }));
// Path parameters
app.get('/users/:id', async (c) => {
const id = c.req.param('id');
const user = await getUserById(id);
return c.json(user);
});
// POST with body parsing
app.post('/users', async (c) => {
const body = await c.req.json<{ name: string; email: string }>();
const user = await createUser(body);
return c.json(user, 201);
});
export default app;
The export default app pattern works across all runtimes.
TypeScript with Zod Validation
import { Hono } from 'hono';
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';
const userSchema = z.object({
name: z.string().min(2),
email: z.string().email(),
age: z.number().int().positive(),
});
const app = new Hono();
app.post('/users', zValidator('json', userSchema), async (c) => {
const data = c.req.valid('json'); // Fully typed: { name, email, age }
const user = await createUser(data);
return c.json(user, 201);
});
Hono RPC (Type-Safe Client)
// Server
import { Hono } from 'hono';
const app = new Hono()
.get('/users/:id', (c) => c.json({ id: c.req.param('id'), name: 'Alice' }))
.post('/users', zValidator('json', userSchema), (c) => c.json(c.req.valid('json')));
export type AppType = typeof app;
// Client (in a separate file)
import { hc } from 'hono/client';
import type { AppType } from './app';
const client = hc<AppType>('http://localhost:3000');
// Fully typed response:
const response = await client.users.$get();
const user = await response.json(); // TypeScript knows the shape
Middleware
import { logger } from 'hono/logger';
import { cors } from 'hono/cors';
import { bearerAuth } from 'hono/bearer-auth';
app.use('*', logger());
app.use('/api/*', cors());
app.use('/api/admin/*', bearerAuth({ token: process.env.API_TOKEN }));
ElysiaJS
Package: elysia
Weekly downloads: 300K
GitHub stars: 11K
Creator: Bogeychan, Saltyaom
ElysiaJS is designed specifically for Bun. While it runs on other runtimes, it's optimized for Bun's performance characteristics.
Installation
bun install elysia
Basic Usage
import { Elysia, t } from 'elysia';
const app = new Elysia()
.get('/', () => 'Hello World!')
.get('/json', () => ({ message: 'Hello', status: 'ok' }))
.post('/users', ({ body }) => createUser(body), {
body: t.Object({
name: t.String({ minLength: 2 }),
email: t.String({ format: 'email' }),
age: t.Integer({ minimum: 0 }),
}),
})
.listen(3000);
console.log(`Running at ${app.server?.hostname}:${app.server?.port}`);
Elysia uses its own TypeBox-based schema validation system (t), which is faster than Zod for runtime validation.
Eden Treaty: End-to-End Type Safety
Elysia's killer feature — type-safe client without code generation:
// server.ts
import { Elysia, t } from 'elysia';
const app = new Elysia()
.get('/users/:id', ({ params }) => getUser(params.id))
.post('/users', ({ body }) => createUser(body), {
body: t.Object({ name: t.String(), email: t.String() }),
});
export type App = typeof app;
// client.ts
import { treaty } from '@elysiajs/eden';
import type { App } from './server';
const client = treaty<App>('http://localhost:3000');
// TypeScript knows everything about the API:
const { data: user } = await client.users({ id: '123' }).get();
const { data: newUser } = await client.users.post({ name: 'Alice', email: 'alice@example.com' });
No schema duplication. No code generation. Types are inferred directly from the server definition.
Elysia Plugins
import { Elysia } from 'elysia';
import { swagger } from '@elysiajs/swagger';
import { cors } from '@elysiajs/cors';
import { jwt } from '@elysiajs/jwt';
const app = new Elysia()
.use(swagger()) // Auto-generate Swagger docs
.use(cors())
.use(jwt({ secret: process.env.JWT_SECRET! }))
.get('/protected', ({ jwt, headers }) => {
const token = headers.authorization?.replace('Bearer ', '');
const payload = jwt.verify(token);
return payload;
});
Performance
ElysiaJS on Bun benchmarks:
| Framework | Requests/sec (Bun) |
|---|---|
| ElysiaJS | ~280K |
| Hono | ~190K |
| Fastify (Node.js) | ~80K |
| Express (Node.js) | ~40K |
Benchmarks from ElysiaJS's own comparison. Real-world results vary.
Nitro
Package: nitropack
Weekly downloads: 1.5M
GitHub stars: 7K
Creator: UnJS team (Nuxt)
Nitro is different from Hono and Elysia — it's not primarily a framework for building APIs. It's a universal server layer for building frameworks and meta-frameworks. It powers Nuxt.js and is the foundation that frameworks build on.
What Nitro Provides
- H3: The underlying HTTP framework (like Hono but from UnJS)
- Auto-imports: Files in
/apifolder become API routes automatically - File-based routing: API routes via filesystem (
/api/users/[id].ts) - Adapters: Deploy to Cloudflare, Vercel, AWS Lambda, Node.js with the same code
- Bundling: Rollup-based bundling with tree-shaking
When to Use Nitro
// In a Nuxt 3 app, this is automatic:
// server/api/users/[id].ts
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, 'id');
const user = await getUserById(id);
return user; // Automatically serialized to JSON
});
Standalone Nitro
// nitro.config.ts
export default defineNitroConfig({
routeRules: {
'/api/**': { cors: true },
},
preset: 'cloudflare-workers', // Deploy target
});
// routes/api/users.ts
export default defineEventHandler(async (event) => {
const users = await db.user.findMany();
return users;
});
npx nitro dev
npx nitro build # Outputs to .output/
H3: Nitro's Core HTTP Framework
H3 is the actual HTTP framework inside Nitro, similar to Hono but from the UnJS ecosystem:
import { createApp, defineEventHandler, getRouterParam, createRouter, readBody } from 'h3';
const app = createApp();
const router = createRouter();
router.get('/users/:id', defineEventHandler((event) => {
const id = getRouterParam(event, 'id');
return { id, name: 'Alice' };
}));
app.use(router);
export default app;
Performance Comparison
| Framework | Requests/sec (Node.js) | Runtime Support | TypeScript Safety |
|---|---|---|---|
| ElysiaJS | ~280K (Bun) | Bun-first | End-to-end (Eden) |
| Hono | ~120K | Universal | RPC (hc) |
| H3/Nitro | ~90K | Universal | Good |
| Fastify | ~80K | Node.js | Plugins |
| Express | ~40K | Node.js | Types only |
Feature Comparison
| Feature | Hono | ElysiaJS | Nitro/H3 |
|---|---|---|---|
| Runtime support | 9+ (universal) | Bun-first | Universal |
| Bundle size | <14 kB | ~22 kB | Large |
| End-to-end types | RPC (hc) | Eden (yes) | No |
| Auto-imports | No | No | Yes |
| File-based routing | No | No | Yes |
| Plugin system | Middleware | Rich | Adapters |
| Weekly downloads | 2M | 300K | 1.5M (Nuxt) |
| Best use case | Edge APIs | Bun APIs | Meta-frameworks |
Decision Guide
Choose Hono if:
- Building an API that needs to run on edge runtimes (Cloudflare Workers)
- Multi-runtime support is important
- You want a simple, Express-like API with TypeScript
- Building microservices or serverless functions
- Portability across cloud providers is a requirement
Choose ElysiaJS if:
- You're committed to Bun as your runtime
- End-to-end type safety (Eden) is important
- Maximum throughput on Bun is needed
- You like the TypeBox validation approach
- Building a full-stack TypeScript app with Bun
Choose Nitro/H3 if:
- Building a meta-framework or universal server layer
- You're in the Nuxt/UnJS ecosystem
- File-based API routing is important
- You need flexible deployment adapters as a primary concern
The 2026 Recommendation
For new API projects: Start with Hono. Its universal runtime support future-proofs you, and the TypeScript + Zod integration is excellent. If you switch to edge deployment later, no code changes needed.
For Bun-committed teams: ElysiaJS's performance and Eden type safety are compelling. The Bun ecosystem is maturing and the performance advantage is real.
For Nuxt/framework development: Nitro/H3 is the right abstraction layer — it's what you use when building for the ecosystem, not for end applications.
Compare package download trends on PkgPulse.
Compare Hono, Elysiajs, and Nitro package health on PkgPulse.
See the live comparison
View hono vs. elysiajs vs nitro on PkgPulse →