What Elysia Does
- End-to-End Type Safety: TypeScript inference from server to client (like tRPC)
- High Performance: 20x faster than Express, 2x faster than Fastify
- Schema Validation: Built-in validation via TypeBox (JSON Schema + TypeScript)
- OpenAPI: Automatic Swagger/OpenAPI documentation generation
- WebSocket: First-class WebSocket support
- Plugin System: Composable plugins with type safety
- File Upload: Native multipart/form-data handling
- Streams: Response streaming (SSE, generators)
- Cookie/Session: Built-in cookie handling
- JWT: Native JWT plugin
- CORS: Simple CORS configuration
- Rate Limiting: Built-in rate limiter
- Static Files: Serve static assets
Basic Example
Hello World
// src/index.ts
import { Elysia } from 'elysia';
const app = new Elysia()
.get('/', () => 'Hello Elysia')
.listen(3000);
console.log(`🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`);Run with:
bun run src/index.tsWith Validation
import { Elysia, t } from 'elysia';
const app = new Elysia()
.post('/users', ({ body }) => {
// body is fully typed!
return { created: body };
}, {
body: t.Object({
name: t.String({ minLength: 1, maxLength: 100 }),
email: t.String({ format: 'email' }),
age: t.Number({ minimum: 0, maximum: 150 }),
}),
})
.listen(3000);Path Parameters
new Elysia()
.get('/users/:id', ({ params }) => {
// params.id is typed as string
return { id: params.id };
}, {
params: t.Object({
id: t.String(),
}),
})
.get('/posts/:year/:slug', ({ params }) => {
return params; // { year: string, slug: string }
})Full CRUD Example
import { Elysia, t } from 'elysia';
import { swagger } from '@elysiajs/swagger';
const users = new Map();
const app = new Elysia()
.use(swagger()) // Auto OpenAPI docs at /swagger
// Create
.post('/users', ({ body, set }) => {
const id = crypto.randomUUID();
const user = { id, ...body };
users.set(id, user);
set.status = 201;
return user;
}, {
body: t.Object({
name: t.String(),
email: t.String({ format: 'email' }),
}),
})
// Read all
.get('/users', () => {
return Array.from(users.values());
})
// Read one
.get('/users/:id', ({ params, error }) => {
const user = users.get(params.id);
if (!user) return error(404, 'User not found');
return user;
})
// Update
.put('/users/:id', ({ params, body, error }) => {
if (!users.has(params.id)) return error(404, 'User not found');
const updated = { id: params.id, ...body };
users.set(params.id, updated);
return updated;
}, {
body: t.Object({
name: t.String(),
email: t.String({ format: 'email' }),
}),
})
// Delete
.delete('/users/:id', ({ params, error }) => {
if (!users.delete(params.id)) return error(404, 'User not found');
return { deleted: true };
})
.listen(3000);Key Features
Schema-First with TypeBox
import { Elysia, t } from 'elysia';
const UserSchema = t.Object({
id: t.String(),
name: t.String({ minLength: 1 }),
email: t.String({ format: 'email' }),
age: t.Number({ minimum: 0 }),
role: t.Union([t.Literal('admin'), t.Literal('user')]),
tags: t.Array(t.String()),
});
// Infer TypeScript type from schema
type User = typeof UserSchema.static;Plugins
import { Elysia } from 'elysia';
import { cors } from '@elysiajs/cors';
import { jwt } from '@elysiajs/jwt';
import { swagger } from '@elysiajs/swagger';
import { staticPlugin } from '@elysiajs/static';
import { html } from '@elysiajs/html';
const app = new Elysia()
.use(cors({
origin: 'https://example.com',
credentials: true,
}))
.use(jwt({
name: 'jwt',
secret: process.env.JWT_SECRET!,
}))
.use(swagger({
documentation: {
info: {
title: 'My API',
version: '1.0.0',
},
},
}))
.use(staticPlugin({ prefix: '/public' }))
.use(html())
.listen(3000);Authentication with JWT
import { Elysia } from 'elysia';
import { jwt } from '@elysiajs/jwt';
new Elysia()
.use(jwt({
name: 'jwt',
secret: 'super-secret-key',
}))
.post('/login', async ({ jwt, body, cookie: { auth } }) => {
// Verify credentials (omitted)
const token = await jwt.sign({ userId: '123', role: 'admin' });
auth.set({ value: token, maxAge: 7 * 86400, path: '/' });
return { success: true };
})
.get('/profile', async ({ jwt, cookie: { auth }, error }) => {
const payload = await jwt.verify(auth.value);
if (!payload) return error(401, 'Unauthorized');
return { userId: payload.userId };
})
.listen(3000);WebSocket Support
new Elysia()
.ws('/chat', {
// Schema for messages
body: t.Object({
message: t.String(),
userId: t.String(),
}),
open(ws) {
ws.subscribe('chatroom');
console.log('Client connected');
},
message(ws, { message, userId }) {
// Broadcast to all in chatroom
ws.publish('chatroom', {
message,
userId,
timestamp: Date.now(),
});
},
close(ws) {
ws.unsubscribe('chatroom');
},
})
.listen(3000);End-to-End Type Safety (Eden)
// server.ts - export app type
import { Elysia } from 'elysia';
const app = new Elysia()
.get('/users/:id', ({ params }) => ({
id: params.id,
name: 'John',
}))
.listen(3000);
export type App = typeof app;// client.ts - fully typed client
import { treaty } from '@elysiajs/eden';
import type { App } from './server';
const client = treaty<App>('localhost:3000');
// Fully typed!
const { data, error } = await client.users({ id: '123' }).get();
// data is { id: string, name: string } | null
// error is typed tooDerived State & Lifecycle
new Elysia()
// Run before every handler
.derive(({ request }) => {
const userAgent = request.headers.get('user-agent');
return { userAgent };
})
// Access derived state
.get('/', ({ userAgent }) => ({
message: 'Hello',
userAgent,
}))
// Lifecycle hooks
.onRequest(({ request }) => {
console.log(`Request: ${request.method} ${request.url}`);
})
.onBeforeHandle(({ set }) => {
set.headers['x-powered-by'] = 'Elysia';
})
.onAfterHandle(() => {
console.log('Request completed');
})
.onError(({ code, error }) => {
console.error(`Error ${code}:`, error);
})
.listen(3000);Performance Benchmarks
Plain text response benchmark (requests/sec on same hardware):
Bun + Elysia: 350,000 req/s ←
Bun + Hono: 320,000 req/s
Go + Fiber: 290,000 req/s
Node + Fastify: 95,000 req/s
Node + Express: 15,000 req/sElysia is one of the fastest JavaScript frameworks, leveraging Bun's speed.
Elysia vs Alternatives
| Feature | Elysia | Hono | Fastify | Express |
|---|---|---|---|---|
| Runtime | Bun (primary) | Bun/Node/Workers | Node | Node |
| Performance | Extreme | Very high | High | Low |
| Type safety | End-to-end | Good | Basic | None |
| Validation | Built-in (TypeBox) | Zod via plugin | Schema | Manual |
| OpenAPI | Built-in | Plugin | Plugin | Plugin |
| WebSocket | Built-in | Built-in | Plugin | ws library |
| Eden client | Yes (like tRPC) | Hono client | No | No |
| Ecosystem | Growing | Growing | Mature | Mature |
常见问题
Q: Elysia 必须用 Bun 吗? A: Elysia 为 Bun 优化,但也支持 Node.js 和 Cloudflare Workers。不过,Elysia 在 Bun 上性能最佳,推荐使用 Bun。
Q: 和 tRPC 怎么选? A: tRPC 只做 RPC 风格 API,不处理 HTTP 路由细节。Elysia 是完整的 HTTP 框架(REST + WebSocket + 静态文件),同时通过 Eden 提供 tRPC 式的端到端类型安全。如果你需要传统 HTTP API + 类型安全,选 Elysia。
Q: 生产就绪吗? A: Elysia 1.0 已于 2024 年发布,API 稳定。被许多公司用于生产环境。Bun 也已进入生产就绪状态。对于新 TypeScript API 项目,这是一个优秀的选择。
来源与致谢
- GitHub: elysiajs/elysia — 17.9K+ ⭐ | MIT
- 官网: elysiajs.com