はじめに
正直なところ、Node.js向けのWebフレームワークって選び放題すぎて困りますよね。
Express、Fastify、Hono、Nest.js...どれを選んでも一長一短があって、「これだ」という決め手に欠ける。そんな中で最近注目しているのがElysiaというフレームワークです。
ElysiaはGitHubで15,700スター以上を獲得している、Bunランタイムに最適化されたTypeScriptフレームワーク。「Ergonomic Framework for Humans(人間のための人間工学的フレームワーク)」というコンセプトを掲げていて、開発者体験を徹底的に追求しています。
そして何より、Express比で21倍、Fastify比で6倍高速という驚異的なパフォーマンス。これ、ベンチマーク詐欺じゃないんですよ。TechEmpower Benchmark Round 22の公式結果です。
Elysiaとは
Elysiaは、Bunランタイム上で動作することを前提に設計されたTypeScriptファーストのWebフレームワークです。バージョン1.4.18(2025年12月時点)がリリースされており、99人のコントリビューターによって活発に開発が続けられています。
最大の特徴は、エンドツーエンドの型安全性。リクエストのバリデーションから、レスポンスの型、さらにはフロントエンドとの連携まで、すべてがTypeScriptの型システムで保護されます。
公式サイト: https://elysiajs.com GitHub: https://github.com/elysiajs/elysia
特徴・メリット
1. 圧倒的なパフォーマンス
Bunの性能を最大限に引き出す設計になっていて、処理速度が桁違いです。
Express: 約 15,000 req/sec
Fastify: 約 50,000 req/sec
Elysia: 約 300,000 req/sec
30代になって思うのは、「速いは正義」ということ。サーバーコストの削減、ユーザー体験の向上、開発時のストレス軽減。速さはすべてを解決する。
2. エンドツーエンドの型安全性
これ、意外と他のフレームワークにはない強みなんですよ。
import { Elysia, t } from 'elysia'
const app = new Elysia()
.post('/user', ({ body }) => {
// bodyの型が自動的に { name: string, age: number } になる
return { id: 1, ...body }
}, {
body: t.Object({
name: t.String(),
age: t.Number()
})
})
スキーマを定義すれば、TypeScriptが自動的に型を推論してくれます。バリデーションと型定義が一体化しているので、「バリデーションは通ったけど型が違う」みたいな事故が起きない。
3. Eden Treaty - フロントエンドとの完全な型共有
個人的にはこれが一番の推しポイントです。
// バックエンド側
const app = new Elysia()
.get('/api/users', () => [{ id: 1, name: 'easegis' }])
.listen(3000)
export type App = typeof app
// フロントエンド側
import { treaty } from '@elysiajs/eden'
import type { App } from './server'
const client = treaty<App>('http://localhost:3000')
// 完全に型安全なAPIコール
const { data } = await client.api.users.get()
// data の型は自動的に { id: number, name: string }[] になる
tRPCみたいなことがフレームワーク標準でできます。コスパ的にこれはかなりデカい。
4. 直感的で洗練されたAPI
メソッドチェーンで直感的にルーティングを定義できます。
new Elysia()
.get('/', 'Hello World') // 文字列をそのまま返せる
.get('/json', { hello: 'world' }) // オブジェクトは自動でJSON化
.post('/echo', ({ body }) => body) // リクエストボディをそのまま返す
.listen(3000)
Expressを使ってた人なら、この書き心地の良さがわかると思います。
5. 複数のバリデーターに対応
Zodが好きな人はZod、Valibotが好きな人はValibot。好みのバリデーターを使えます。
import { Elysia } from 'elysia'
import { z } from 'zod'
const userSchema = z.object({
name: z.string(),
email: z.string().email()
})
new Elysia()
.post('/user', ({ body }) => body, {
body: userSchema
})
既存のZodスキーマをそのまま流用できるのは、移行コストの面でありがたい。
インストール方法
前提条件
ElysiaはBunランタイムを前提としています。まずBunをインストールしてください。
# macOS / Linux
curl -fsSL https://bun.sh/install | bash
# Windows
powershell -c "irm bun.sh/install.ps1 | iex"
新規プロジェクトの作成
bun create elysia app
cd app
bun run dev
これだけでHot Reload対応の開発サーバーが立ち上がります。時短になりますね。
既存プロジェクトへの追加
bun add elysia
Eden Treaty(フロントエンド連携)を使う場合
bun add @elysiajs/eden
基本的な使い方
Hello World
// src/index.ts
import { Elysia } from 'elysia'
new Elysia()
.get('/', 'Hello World')
.listen(3000)
console.log('Server is running on http://localhost:3000')
bun run src/index.ts
シンプルですね。Expressの冗長さと比べると、このミニマルさは清々しい。
ルーティング
import { Elysia } from 'elysia'
const app = new Elysia()
// GETリクエスト
.get('/users', () => [{ id: 1, name: 'User' }])
// POSTリクエスト
.post('/users', ({ body }) => {
return { id: 2, ...body }
})
// パスパラメータ
.get('/users/:id', ({ params: { id } }) => {
return { id: parseInt(id), name: 'User' }
})
// クエリパラメータ
.get('/search', ({ query }) => {
return { keyword: query.q }
})
.listen(3000)
バリデーション
import { Elysia, t } from 'elysia'
const app = new Elysia()
.post('/user', ({ body }) => {
return { success: true, data: body }
}, {
body: t.Object({
name: t.String({ minLength: 1 }),
email: t.String({ format: 'email' }),
age: t.Optional(t.Number({ minimum: 0 }))
}),
response: t.Object({
success: t.Boolean(),
data: t.Object({
name: t.String(),
email: t.String(),
age: t.Optional(t.Number())
})
})
})
.listen(3000)
リクエストもレスポンスも型安全。これがElysiaの真骨頂です。
プラグインシステム
機能をモジュール化して再利用できます。
import { Elysia } from 'elysia'
// 認証プラグイン
const authPlugin = new Elysia({ name: 'auth' })
.derive(({ headers }) => {
const token = headers.authorization?.replace('Bearer ', '')
return { userId: token ? 'user-123' : null }
})
// メインアプリ
const app = new Elysia()
.use(authPlugin)
.get('/profile', ({ userId }) => {
if (!userId) return { error: 'Unauthorized' }
return { userId }
})
.listen(3000)
実践的なユースケース
1. REST APIサーバーの構築
import { Elysia, t } from 'elysia'
import { cors } from '@elysiajs/cors'
interface Todo {
id: number
title: string
completed: boolean
}
let todos: Todo[] = []
let nextId = 1
const app = new Elysia()
.use(cors())
// 一覧取得
.get('/api/todos', () => todos)
// 作成
.post('/api/todos', ({ body }) => {
const todo: Todo = { id: nextId++, ...body, completed: false }
todos.push(todo)
return todo
}, {
body: t.Object({
title: t.String({ minLength: 1 })
})
})
// 更新
.patch('/api/todos/:id', ({ params, body }) => {
const todo = todos.find(t => t.id === parseInt(params.id))
if (!todo) return { error: 'Not found' }
Object.assign(todo, body)
return todo
}, {
body: t.Object({
title: t.Optional(t.String()),
completed: t.Optional(t.Boolean())
})
})
// 削除
.delete('/api/todos/:id', ({ params }) => {
const index = todos.findIndex(t => t.id === parseInt(params.id))
if (index === -1) return { error: 'Not found' }
todos.splice(index, 1)
return { success: true }
})
.listen(3000)
console.log('API Server running on http://localhost:3000')
2. WebSocket対応リアルタイムアプリ
import { Elysia } from 'elysia'
const app = new Elysia()
.ws('/chat', {
message(ws, message) {
// 全クライアントにブロードキャスト
ws.publish('chat', message)
},
open(ws) {
ws.subscribe('chat')
ws.send('Welcome to the chat!')
}
})
.listen(3000)
WebSocketが標準対応なのは嬉しいポイント。Socket.ioなしでリアルタイム通信が実装できます。
3. OpenAPIドキュメント自動生成
import { Elysia, t } from 'elysia'
import { swagger } from '@elysiajs/swagger'
const app = new Elysia()
.use(swagger({
documentation: {
info: {
title: 'My API',
version: '1.0.0'
}
}
}))
.get('/users', () => [{ id: 1, name: 'User' }], {
detail: {
summary: 'ユーザー一覧を取得',
tags: ['users']
}
})
.listen(3000)
// http://localhost:3000/swagger でドキュメントが見れる
型定義からSwagger UIが自動生成されます。ドキュメントを別途書く必要がない。
公式プラグイン
Elysiaには便利な公式プラグインが揃っています。
| プラグイン | 用途 |
|---|---|
| @elysiajs/cors | CORS対応 |
| @elysiajs/swagger | OpenAPIドキュメント生成 |
| @elysiajs/jwt | JWT認証 |
| @elysiajs/cookie | Cookie操作 |
| @elysiajs/static | 静的ファイル配信 |
| @elysiajs/eden | フロントエンド連携 |
注意点
いいことばかり書いてきましたが、注意点もあります。
1. Bun依存
ElysiaはBunに最適化されています。Node.jsでも動くようになっていますが、パフォーマンスを最大限発揮するにはBunが必要です。
2. エコシステムはまだ発展途上
ExpressやFastifyと比べると、サードパーティのミドルウェアは少なめ。ただ、公式プラグインで主要なユースケースはカバーされています。
3. 学習コスト
独自の概念(derive、decorateなど)があるので、最初は少し戸惑うかもしれません。ただ、一度理解すれば非常に直感的です。
まとめ
正直なところ、ElysiaがExpress/Fastifyを完全に置き換えるかはまだわかりません。でも、以下の条件に当てはまるなら、試してみる価値は間違いなくあります:
- Bunを使っている、または使いたい
- TypeScriptで型安全なAPIを構築したい
- パフォーマンスを重視したい
- フロントエンドとの型共有を実現したい
- モダンな開発体験を求めている
個人的には、新規のAPIサーバー開発ならElysia一択ですね。ExpressからのマイグレーションもAPIの互換性が高いので、段階的に移行できます。
BunとElysiaの組み合わせは、2024年以降のバックエンド開発のスタンダードになる可能性を感じています。まずは小さなプロジェクトで試してみてください。QOL上がること間違いなしです。
公式サイト: https://elysiajs.com GitHub: https://github.com/elysiajs/elysia ドキュメント: https://elysiajs.com/introduction.html