# Elysia — Ergonomic TypeScript Web Framework for Bun > Elysia is a fast, ergonomic TypeScript web framework optimized for Bun runtime. End-to-end type safety, OpenAPI support, and performance that rivals Go and Rust frameworks. ## Install Save the content below to `.claude/skills/` or append to your `CLAUDE.md`: ## Quick Use ```bash # Bootstrap a new Elysia project bun create elysia my-app cd my-app bun run dev ``` ## Intro **Elysia** is a fast, ergonomic TypeScript web framework designed for the Bun runtime. It prioritizes both developer experience and performance — providing end-to-end type safety via TypeScript inference, intuitive APIs, and performance that often surpasses Express, Fastify, and even matches Go frameworks like Gin. With 17.9K+ GitHub stars and MIT license, Elysia has become the go-to framework for developers building APIs with Bun, offering a refreshing alternative to the Node.js ecosystem with modern DX and superior performance. ## 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 ```typescript // 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: ```bash bun run src/index.ts ``` ### With Validation ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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) ```typescript // 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; ``` ```typescript // client.ts - fully typed client import { treaty } from '@elysiajs/eden'; import type { App } from './server'; const client = treaty('localhost:3000'); // Fully typed! const { data, error } = await client.users({ id: '123' }).get(); // data is { id: string, name: string } | null // error is typed too ``` ### Derived State & Lifecycle ```typescript 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/s ``` Elysia 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 | ## FAQ **Q: Does Elysia require Bun?** A: Elysia is optimized for Bun, but it also supports Node.js and Cloudflare Workers. That said, Elysia performs best on Bun, so Bun is the recommended runtime. **Q: Elysia or tRPC — which should I choose?** A: tRPC only does RPC-style APIs and doesn't handle HTTP routing details. Elysia is a full HTTP framework (REST + WebSocket + static files) and, via Eden, provides tRPC-like end-to-end type safety. If you need traditional HTTP APIs with type safety, pick Elysia. **Q: Is it production-ready?** A: Elysia 1.0 was released in 2024 with a stable API. It's used in production by many companies. Bun has also reached production-ready status. For new TypeScript API projects, this is an excellent choice. ## Sources & Credits - GitHub: [elysiajs/elysia](https://github.com/elysiajs/elysia) — 17.9K+ ⭐ | MIT - Official site: [elysiajs.com](https://elysiajs.com) --- Source: https://tokrepo.com/en/workflows/elysia-ergonomic-typescript-web-framework-bun-bb30e2f1 Author: Script Depot