express、fastify、hapi、koa は、Node.js 環境で Web サーバーや API を構築するための代表的なフレームワークです。フロントエンド開発者が BFF(Backend for Frontend)や SSR 用のサーバーサイドロジックを実装する際、これらの選択肢が登場します。express は事実上の標準として広大なエコシステムを持ち、fastify は性能とスキーマ検証に優れています。koa は非同期処理に特化した軽量設計であり、hapi は設定重視のエンタープライズ向けアプローチを取ります。それぞれ設計思想が異なるため、プロジェクトの要件に合わせて慎重に選ぶ必要があります。
Node.js でサーバーサイドを構築する際、express、fastify、hapi、koa の 4 つが主要な選択肢となります。フロントエンド開発者が BFF や API サーバーを担う場合、これらの違いを理解することは重要です。単に「速い」「遅い」だけでなく、コードの書き方、エラー処理、そしてメンテナンス性に大きな違いがあります。
各フレームワークは、サーバーの立ち上げ方とリクエストの受け付け方に違いがあります。
express は最もシンプルで、関数ベースのミドルウェアを使います。
// express: 基本サーバー
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello Express');
});
app.listen(3000);
fastify はインスタンスを作成し、スキーマ定義を容易にします。
// fastify: 基本サーバー
const fastify = require('fastify')({ logger: true });
fastify.get('/', async (request, reply) => {
return { hello: 'Hello Fastify' };
});
fastify.listen({ port: 3000 });
hapi は設定オブジェクトを通じてサーバーを定義します。
// hapi: 基本サーバー
const Hapi = require('@hapi/hapi');
const init = async () => {
const server = Hapi.server({ port: 3000, host: 'localhost' });
server.route({
method: 'GET',
path: '/',
handler: (request, h) => {
return 'Hello Hapi';
}
});
await server.start();
};
koa は非同期関数を核心に置き、ctx オブジェクトを使います。
// koa: 基本サーバー
const Koa = require('koa');
const app = new Koa();
app.use(async ctx => {
ctx.body = 'Hello Koa';
});
app.listen(3000);
リクエストとレスポンスをどう扱うかは、開発体験に直結します。
express は req と res オブジェクトを直接操作します。ミドルウェアは next() を呼び出して制御します。
// express: ミドルウェア
app.use((req, res, next) => {
console.log(req.url);
next();
});
fastify は request と reply を使います。エンコーディングやシリアライズが自動最適化されます。
// fastify: ミドルウェア
fastify.addHook('preHandler', async (request, reply) => {
console.log(request.url);
});
hapi は request と h (h toolkit) を使います。拡張性が高いですが、記述量が増えます。
// hapi: ミドルウェア(拡張機能)
server.ext('onRequest', (request, h) => {
console.log(request.path);
return h.continue;
});
koa は単一の ctx オブジェクトに全てを集約します。非同期フローが自然に書けます。
// koa: ミドルウェア
app.use(async (ctx, next) => {
console.log(ctx.url);
await next();
});
API 開発において、入力データの検証は必須です。ここで大きな差が出ます。
express は標準で検証機能を持ちません。joi や zod などのライブラリを自分で組み込む必要があります。
// express: 手動検証が必要
app.post('/user', (req, res) => {
if (!req.body.email) {
return res.status(400).send('Email required');
}
// 処理...
});
fastify は JSON Schema ベースの検証がビルトインされています。設定するだけで自動検証されます。
// fastify: スキーマ検証
fastify.post('/user', {
schema: {
body: {
type: 'object',
required: ['email'],
properties: { email: { type: 'string' } }
}
}
}, async (request, reply) => {
return { status: 'ok' }; // 検証失敗時は自動エラー
});
hapi も joi をベースとした強力な検証機能を持っています。
// hapi: 検証ルール
server.route({
method: 'POST',
path: '/user',
options: {
validate: {
payload: { email: Joi.string().required() }
}
},
handler: (request, h) => ({ status: 'ok' })
});
koa は Express と同様、検証ライブラリの追加が必要です。
// koa: 手動検証が必要
app.use(async ctx => {
if (!ctx.request.body.email) {
ctx.status = 400;
ctx.body = 'Email required';
return;
}
});
予期せぬエラーをどうキャッチするかは、システムの安定性に影響します。
express は next(err) を使ってエラーを伝播させ、専用のエラーハンドラミドルウェアで受けます。
// express: エラーハンドリング
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
fastify は try/catch または専用のエラーハンドラフックを使います。
// fastify: エラーハンドリング
fastify.setErrorHandler((error, request, reply) => {
reply.status(500).send({ error: error.message });
});
hapi は boom などのツールを使い、レスポンスオブジェクトでエラーを表現します。
// hapi: エラーハンドリング
handler: (request, h) => {
throw Boom.badImplementation('Server error');
}
koa は try/catch をミドルウェア内で明示的に書くか、アプリレベルのイベントで受けます。
// koa: エラーハンドリング
app.on('error', err => {
console.error('app error', err);
});
| 特徴 | express | fastify | hapi | koa |
|---|---|---|---|---|
| 設計思想 | 最小限・自由度高 | 性能・検証重視 | 設定重視・堅牢 | 非同期・軽量 |
| バリデーション | 外部ライブラリ必要 | ビルトイン | ビルトイン | 外部ライブラリ必要 |
| 非同期処理 | コールバック混在 | Async/Await | Async/Await | Async/Await |
| エコシステム | 最大 | 成長中 | 安定・縮小傾向 | 中規模 |
| 学習コスト | 低い | 中 | 高い | 中 |
express は、迷ったときの安全策です。ドキュメントやサードパーティ製ミドルウェアが圧倒的に多く、フロントエンド開発者がサーバーサイドに初めて触れる場合にも最適です。ただし、性能最適化や検証ロジックは自分で組む必要があります。
fastify は、現代の API 開発において最もバランスが取れています。検証機能が含まれているため、コード量が減り、パフォーマンスも優れています。新規プロジェクトで迷ったら、まず fastify を検討する価値があります。
hapi は、設定による制御を好む大規模システムで依然として使われています。しかし、コミュニティの活動は以前より落ち着いているため、新規採用には慎重になるべきです。
koa は、Express のモダンな後継として作られましたが、フル機能フレームワークというよりはライブラリに近いです。独自のミドルウェア構造を理解できる上級者向けです。
最終的には、チームの習熟度とプロジェクトの規模で決まります。性能と開発効率を両立したいなら fastify、既存資産や情報量を重視するなら express が妥当な選択でしょう — どちらを選んでも、Node.js のエコシステム内で十分なサポートが得られます。
既存のミドルウェアや教程リソースをすぐに活用したい場合に express を選定します。コミュニティが非常に大きく、問題が起きた際の解決策が見つかりやすいのが強みです。レガシーシステムとの統合や、標準的な CRUD API を 빠르게構築するプロジェクトに適しています。
非同期処理を深く理解し、ミドルウェアの挙動を細かく制御したい場合に koa を選びます。Express の創作者によって作られており、よりモダンな async/await 設計です。軽量なプロキシサーバーや、カスタムな処理パイプラインを組む際に適しています。
高いスループットと低いレイテンシが求められる場合、fastify が最適です。ビルトインのスキーマ検証機能により、入力データの検証コードを削減できます。マイクロサービス架构や、性能が重要な本番環境での API 開発に向いています。
設定による制御を好み、堅牢なエンタープライズ環境で運用されている場合に hapi を検討します。ただし、近年はエコシステムの変化があるため、新規プロジェクトでは慎重な評価が必要です。既存の hapi 資産を維持するケースで真価を発揮します。
Fast, unopinionated, minimalist web framework for Node.js.
This project has a Code of Conduct.
import express from 'express'
const app = express()
app.get('/', (req, res) => {
res.send('Hello World')
})
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000')
})
This is a Node.js module available through the npm registry.
Before installing, download and install Node.js. Node.js 18 or higher is required.
If this is a brand new project, make sure to create a package.json first with
the npm init command.
Installation is done using the
npm install command:
npm install express
Follow our installing guide for more information.
PROTIP Be sure to read the migration guide to v5
The quickest way to get started with express is to utilize the executable express(1) to generate an application as shown below:
Install the executable. The executable's major version will match Express's:
npm install -g express-generator@4
Create the app:
express /tmp/foo && cd /tmp/foo
Install dependencies:
npm install
Start the server:
npm start
View the website at: http://localhost:3000
The Express philosophy is to provide small, robust tooling for HTTP servers, making it a great solution for single page applications, websites, hybrids, or public HTTP APIs.
Express does not force you to use any specific ORM or template engine. With support for over 14 template engines via @ladjs/consolidate, you can quickly craft your perfect framework.
To view the examples, clone the Express repository:
git clone https://github.com/expressjs/express.git --depth 1 && cd express
Then install the dependencies:
npm install
Then run whichever example you want:
node examples/content-negotiation
The Express.js project welcomes all constructive contributions. Contributions take many forms, from code for bug fixes and enhancements, to additions and fixes to documentation, additional tests, triaging incoming pull requests and issues, and more!
See the Contributing Guide for more technical details on contributing.
If you discover a security vulnerability in Express, please see Security Policies and Procedures.
To run the test suite, first install the dependencies:
npm install
Then run npm test:
npm test
For information about the governance of the express.js project, see GOVERNANCE.md.
The original author of Express is TJ Holowaychuk