ScriptsApr 11, 2026·1 min read

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.

SC
Script Depot · Community
Quick Use

Use it first, then decide how deep to go

This block should tell both the user and the agent what to copy, install, and apply first.

# 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

// 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.ts

With 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 too

Derived 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/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

常见问题

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 项目,这是一个优秀的选择。

来源与致谢

Discussion

Sign in to join the discussion.
No comments yet. Be the first to share your thoughts.

Related Assets