Express handles ~15K req/s. Fastify does ~77K. ElysiaJS on Bun does 2.5 million — and the developer experience is better than both.
Why ElysiaJS
ElysiaJS is built specifically for Bun runtime. It uses:
- Bun's native HTTP server (fastest in JS ecosystem)
- Static code analysis for route compilation
- End-to-end type safety with TypeBox
- Plugin-based architecture
Hello World
import { Elysia } from "elysia";
const app = new Elysia()
.get("/", () => "Hello World")
.get("/users/:id", ({ params: { id } }) => ({ userId: id }))
.listen(3000);
console.log(`Running at http://localhost:${app.server?.port}`);
bun run index.ts
Type-Safe Everything
import { Elysia, t } from "elysia";
const app = new Elysia()
.post("/users", ({ body }) => {
// body is fully typed: { name: string, email: string, age: number }
return { id: crypto.randomUUID(), ...body };
}, {
body: t.Object({
name: t.String({ minLength: 1 }),
email: t.String({ format: "email" }),
age: t.Number({ minimum: 0 }),
}),
response: t.Object({
id: t.String(),
name: t.String(),
email: t.String(),
age: t.Number(),
}),
})
.get("/users", ({ query }) => {
// query.page is typed as number
return { page: query.page, users: [] };
}, {
query: t.Object({
page: t.Number({ default: 1 }),
limit: t.Number({ default: 10 }),
}),
});
Validation + TypeScript types generated from a single schema definition.
Plugins
import { Elysia } from "elysia";
import { swagger } from "@elysiajs/swagger";
import { jwt } from "@elysiajs/jwt";
import { cors } from "@elysiajs/cors";
const app = new Elysia()
.use(swagger()) // Auto-generated Swagger docs at /swagger
.use(cors()) // CORS handling
.use(jwt({ secret: process.env.JWT_SECRET! }))
.post("/login", async ({ jwt, body }) => {
const token = await jwt.sign({ userId: body.userId });
return { token };
})
.get("/protected", async ({ jwt, headers }) => {
const payload = await jwt.verify(headers.authorization?.split(" ")[1]);
if (!payload) throw new Error("Unauthorized");
return { user: payload };
});
Eden (End-to-End Type Safety)
// Client side — like tRPC but for REST
import { edenTreaty } from "@elysiajs/eden";
import type { App } from "./server";
const api = edenTreaty<App>("http://localhost:3000");
// Fully typed — TypeScript knows the response shape
const { data } = await api.users.post({
name: "Alice",
email: "alice@test.com",
age: 30,
});
console.log(data.id); // Typed as string
Groups and Guards
const app = new Elysia()
.group("/api/v1", (app) =>
app
.get("/users", getUsers)
.post("/users", createUser)
)
.guard({ headers: t.Object({ authorization: t.String() }) }, (app) =>
app
.get("/admin/stats", getStats)
.delete("/admin/users/:id", deleteUser)
);
Benchmark
| Framework | Runtime | Requests/sec |
|---|---|---|
| Express | Node.js | ~15,000 |
| Fastify | Node.js | ~77,000 |
| Hono | Bun | ~150,000 |
| ElysiaJS | Bun | ~2,500,000 |
Need high-performance APIs or data solutions? I build web tools and scraping infrastructure. Email spinov001@gmail.com or check my Apify tools.
Top comments (0)