Hono vs ElysiaJS vs Nitro: Lightweight Backend Frameworks 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.
See the live comparison
View hono vs. elysiajs vs nitro on PkgPulse →