express、fastify、hapi、koa、sails は、Node.js 環境で Web サーバーや API を構築するための主要なフレームワークです。express は最も広く使われているミニマルなフレームワークで、柔軟性が特徴です。fastify はパフォーマンスとスキーマベースの検証に重点を置いたモダンな選択肢です。hapi は設定重視のアーキテクチャで、エンタープライズ向けの堅牢性を提供します。koa は Express の創作者によって作られた、より軽量で非同期処理に最適化されたフレームワークです。sails は MVC パターンを採用し、リアルタイム機能や自動 API 生成を含むフルスタックなアプローチを取ります。
Node.js でバックエンドを構築する際、express、fastify、hapi、koa、sails の中からどれを選ぶかは、プロジェクトの規模、パフォーマンス要件、そしてチームの文化に大きく依存します。これらは単に「HTTP サーバー」であるだけでなく、アプリケーションの構造や保守性に直結する設計思想の違いを持っています。実務的な観点から、これら 5 つのフレームワークを比較します。
フレームワークの核となる部分は、リクエストをどのように受け取り、処理するかです。
express は関数型のミドルウェアスタックを採用しています。リクエストとレスポンスオブジェクトを直接操作します。
// express: 基本的なルート定義
const express = require('express');
const app = express();
app.get('/user/:id', (req, res) => {
res.send(`User ID: ${req.params.id}`);
});
fastify は高速化のため、リクエストとレスポンスのラッパーを使用し、スキーマ定義を推奨します。
// fastify: スキーマ付きルート定義
const fastify = require('fastify')();
fastify.get('/user/:id', {
schema: {
params: { id: { type: 'integer' } }
}
}, async (request, reply) => {
reply.send({ id: request.params.id });
});
hapi は設定オブジェクトを通じてルートを定義し、ハンドラー関数は構造化されたデータを返します。
// hapi: 設定ベースのルート定義
const Hapi = require('@hapi/hapi');
const server = Hapi.server({ port: 3000 });
server.route({
method: 'GET',
path: '/user/{id}',
handler: (request, h) => {
return { id: request.params.id };
}
});
koa は Express の創作者によるもので、コンテキストオブジェクト ctx を使用し、非同期フローを制御します。
// koa: コンテキストベースの処理
const Koa = require('koa');
const app = new Koa();
app.use(async ctx => {
ctx.body = `User ID: ${ctx.params.id}`;
});
sails は MVC アーキテクチャを採用し、コントローラーアクションとして処理を記述します。
// sails: コントローラーアクション
// api/controllers/UserController.js
module.exports = {
show: async function (req, res) {
return res.ok({ id: req.param('id') });
}
};
機能を追加する際の仕組みは、フレームワークの拡張性を決定づけます。
express は app.use() を使用して、関数型のミドルウェアをスタックします。サードパーティ製が豊富です。
// express: ミドルウェア使用
const cors = require('cors');
app.use(cors());
app.use((req, res, next) => {
console.log('Time:', Date.now());
next();
});
fastify はプラグインシステムを採用しており、カプセル化されたスコープを持ちます。
// fastify: プラグイン登録
app.register(require('fastify-cors'));
app.register(async function (instance) {
instance.get('/plugin-route', () => { return 'ok' });
});
hapi はプラグイン機能を持ち、サーバーの機能を拡張するために使用されます。
// hapi: プラグイン登録
await server.register({
plugin: require('@hapi/inert') // 静的ファイル提供など
});
koa はミドルウェアを使用しますが、Express と異なりダウンストリームとアップストリームの両方を制御できます。
// koa: 非同期ミドルウェア
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
console.log(`Response time: ${ms}ms`);
});
sails はポリシ(ポリシー)とフックという概念でアクセス制御や機能拡張を行います。
// sails: ポリシ適用
// config/policies.js
module.exports.policies = {
UserController: {
'*': 'isAuthenticated',
show: true
}
};
ユーザー入力の処理はセキュリティの要です。フレームワークごとのアプローチが異なります。
express はデフォルトでは検証機能を持たず、joi や zod などのライブラリをミドルウェアとして組み込む必要があります。
// express: 外部ライブラリでの検証
const { body, validationResult } = require('express-validator');
app.post('/user', [
body('email').isEmail()
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) return res.status(400).json({ errors });
});
fastify は JSON Schema をネイティブにサポートしており、高速な検証が可能です。
// fastify: スキーマベース検証
fastify.post('/user', {
schema: {
body: {
type: 'object',
required: ['email'],
properties: { email: { type: 'string', format: 'email' } }
}
}
}, async (request, reply) => {
// 検証済みデータが request.body にある
});
hapi は joi をベースにした強力な検証機能をルート設定に組み込んでいます。
// hapi: 組み込み検証
server.route({
method: 'POST',
path: '/user',
options: {
validate: {
payload: {
email: Joi.string().email().required()
}
}
},
handler: (request) => { /*...*/ }
});
koa は Express と同様、コアには検証機能が含まれていないため、ミドルウェアを追加します。
// koa: 検証ミドルウェア
const koaBody = require('koa-body');
app.use(koaBody({
onerror: (err, ctx) => {
ctx.throw(400, err);
}
}));
sails は Waterline ORM を通じて、モデル定義時に検証ルールを記述します。
// sails: モデルベース検証
// api/models/User.js
attributes: {
emailAddress: {
type: 'string',
isEmail: true,
required: true
}
}
現代の Node.js 開発において、非同期処理の扱いやすさと実行速度は重要です。
express は伝統的にコールバックスタイルでしたが、現在は async/await が広く使われています。ただし、エラーハンドリングには next(err) が必要です。
// express: エラーハンドリング
app.get('/data', async (req, res, next) => {
try {
const data = await fetchData();
res.json(data);
} catch (err) {
next(err); // エラーを次のハンドラーへ
}
});
fastify は async/await をネイティブにサポートしており、エラーハンドリングがスローするだけで完了します。
// fastify: 自動エラーハンドリング
fastify.get('/data', async (request, reply) => {
const data = await fetchData();
return data; // エラーは自動的に捕捉される
});
hapi も async/await をサポートしており、エラーはスローするか h.response().code() で処理します。
// hapi: 非同期ハンドラー
handler: async (request, h) => {
try {
const data = await fetchData();
return data;
} catch (err) {
throw err; // hapi が捕捉
}
}
koa は最初から async/await 前提で設計されており、ミドルウェアチェーンの制御が直感的です。
// koa: 自然な非同期フロー
app.use(async (ctx, next) => {
ctx.state.data = await fetchData();
await next();
});
sails は内部で Promise を使用しますが、コントローラー構造に従う必要があります。
// sails: 非同期アクション
show: async function (req, res) {
const user = await User.findOne(req.param('id'));
return res.json(user);
}
選択にあたり、メンテナンス状況は重要な要素です。
express は長年維持されており、安定していますが、新機能の追加は緩やかです。レガシーなコードベースが多いことに注意が必要です。
fastify は活発に開発が続いており、パフォーマンスと機能面で現代的な要件を満たしています。新規プロジェクトに推奨されます。
hapi は v21 以降もメンテナンスされており、エンタープライズ用途で安定しています。
koa はメンテナンスされていますが、Express や Fastify に比べると更新頻度は低めです。
sails は過去にメンテナンスが停滞した時期がありましたが、v1 以降も更新は続いています。ただし、エコシステムの規模は他より小さく、新規大規模プロジェクトでの採用は慎重になるべきです。
| 特徴 | express | fastify | hapi | koa | sails |
|---|---|---|---|---|---|
| 哲学 | ミニマル・柔軟 | 高速・スキーマ | 設定重視 | 軽量・非同期 | フルスタック・MVC |
| 検証 | 外部依存 | ネイティブ (JSON Schema) | ネイティブ (Joi) | 外部依存 | モデル定義 |
| 非同期 | Callback/Async | Async 第一 | Async 第一 | Async 第一 | Async 対応 |
| エコシステム | 最大 | 成長中 | 安定 | 中規模 | 小規模 |
| 学習コスト | 低 | 中 | 高 | 中 | 高 |
express は、豊富なリソースとミドルウェアを必要とする場合、あるいは既存の知識資産を活かしたい場合に依然として強力な選択肢です。しかし、パフォーマンスや型安全性を重視する新規プロジェクトでは、fastify がより現代的な代替案となります。
hapi は、大規模な組織で設定ファイルによる統一管理を徹底したい場合に適しています。koa は、Express の軽量化版を求めており、ミドルウェアの制御を細かく行いたい開発者に向いています。
sails は、リアルタイム機能や ORM との密な統合を最初から必要とする場合に有用ですが、フレームワークの制約が強いため、柔軟性を求める場合は避けるべきです。
最終的には、チームのスキルセットとプロジェクトの長期的な保守性を考慮して選定することが重要です。
既存のミドルウェアエコシステムを活用したい場合や、シンプルで慣れ親しんだ構造を好む場合に express を選択します。コミュニティが巨大で、ほぼ全ての要件に対応するサードパーティ製ミドルウェアが存在するため、初期構築のハードルが最も低いです。
ミドルウェアの制御を細かく行いたい、あるいはコールバック地獄を避けたい場合に koa を検討します。Express よりも軽量で、非同期処理の制御が容易ですが、エコシステムは Express よりも小規模です。
高いパフォーマンスと型安全性、そしてスキーマベースの検証を重視する場合は fastify が最適です。プラグインシステムが充実しており、モダンな async/await 構文をネイティブにサポートしているため、新規プロジェクトでの採用が増えています。
設定による制御を好み、セキュリティや入力検証をフレームワークレベルで厳格に管理したい場合に hapi を選定します。コードよりも設定ファイルを重視するアプローチのため、大規模チームでの統一性確保に適しています。
リアルタイム機能(WebSocket)や、データベースとのバインディングを自動で行いたい場合に sails が有効です。MVC 構造が最初から用意されているため、伝統的な Web アプリケーション開発の経験があるチームに適しています。
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