Hono vs Fastify
Hono(エッジファースト、Cloudflare Workers)vs Fastify(Node.jsパフォーマンス)——モダンJS Webフレームワーク比較。パフォーマンス、エッジ互換性、エコシステム。
Nodeエコシステムのデファクトスタンダード:柔軟で成熟した、巨大なミドルウェアの宝庫
スキーマベースでパフォーマンス重視:すべてのルートが一つの契約
Fastifyの公式ベンチマーク(「illustrative(参考値)」との注記付き)はスループットで1.6倍、レイテンシで1.7倍優れており、スキーマベースのシリアライズと公式OpenAPIプラグインに支えられている。Express 5の強みは非同期ハンドラーの自動エラーキャッチだ。GitHubではExpressが大きくリードしている(69,478対37,195スター)。新規かつパフォーマンス重視のサービスならFastify、既存のExpressコードベース+慣れたチームがあるならExpress 5を継続 — 公式の移行ツールは存在しない。
| カテゴリー | Express 5 | Fastify |
|---|---|---|
| パフォーマンス | 6/10 | 9/10 |
| 学習のしやすさ | 9/10 | 7/10 |
| エコシステム | 9/10 | 7/10 |
| コミュニティ | 10/10 | 7/10 |
| 求人市場 | 8/10 | 6/10 |
| 将来性 | 7/10 | 8/10 |
// Express 5 - 非同期ルートハンドラー + 自動エラーキャッチ
import express from 'express';
const app = express();
app.use(express.json());
// シンプルなエラークラス — APIの境界で意味のあるメッセージを返すため
class NotFoundError extends Error {
status = 404;
}
async function getUser(id) {
const user = await db.users.findById(id);
if (!user) throw new NotFoundError('User not found');
return user;
}
// Express 5: 非同期ハンドラーがreject/throwすると、next(err)が自動的に呼ばれる。
// Promiseをreturnし忘れないこと — さもないとrejectionがunhandledのままになる可能性がある。
app.get('/api/users/:id', async (req, res) => {
const user = await getUser(req.params.id);
res.json(user);
});
// 中央集権的なエラーミドルウェア — グローバルスタックの最後に追加される
app.use((err, req, res, next) => {
const status = err.status ?? 500;
res.status(status).json({ error: err.message });
});
app.listen(3000, () => {
console.log('Express server listening on port 3000');
});// Fastify 5 - スキーマバリデーション + 自動シリアライズ
import Fastify from 'fastify';
const fastify = Fastify({ logger: true });
// レスポンススキーマ:fast-json-stringifyがこのスキーマから
// コンパイル済みのシリアライズ関数を生成する — 汎用的なJSON.stringifyより高速。
const userSchema = {
type: 'object',
properties: {
id: { type: 'string' },
name: { type: 'string' },
email: { type: 'string' },
},
required: ['id', 'name', 'email'],
};
const getUserOpts = {
schema: {
params: {
type: 'object',
properties: { id: { type: 'string' } },
required: ['id'],
},
response: {
200: userSchema,
},
},
};
// Encapsulation:このプラグイン内で登録されたhook/decoratorは
// このcontext内のルートにのみ及ぶ。
fastify.register(async function userRoutes(instance) {
instance.get('/api/users/:id', getUserOpts, async (request, reply) => {
const user = await db.users.findById(request.params.id);
if (!user) {
return reply.code(404).send({ error: 'User not found' });
}
request.log.info({ userId: user.id }, 'user fetched');
return user;
});
});
fastify.setErrorHandler((error, request, reply) => {
reply.status(error.statusCode ?? 500).send({ error: error.message });
});
await fastify.listen({ port: 3000 });Fastifyの公式ベンチマーク(「illustrative(参考値)」との注記付き)はスループットで1.6倍、レイテンシで1.7倍優れており、スキーマベースのシリアライズと公式OpenAPIプラグインに支えられている。Express 5の強みは非同期ハンドラーの自動エラーキャッチだ。GitHubではExpressが大きくリードしている(69,478対37,195スター)。新規かつパフォーマンス重視のサービスならFastify、既存のExpressコードベース+慣れたチームがあるならExpress 5を継続 — 公式の移行ツールは存在しない。
無料相談を受ける新規で、パフォーマンスとスキーマバリデーションが重要なサービスを構築するならFastify、既存のExpress資産と慣れたチームがあるならExpress 5。どちらも活発にメンテナンスされている — npmレジストリではexpress@latestが5.2.1、fastify@latestが5.12.5(Fastify v6はalpha段階だが安定版は依然5.x系)— つまり「Expressはもう終わった」という理由で判断してはいけない。サードパーティ製ミドルウェアを幅広く必要とする場合は、天秤はさらにExpress側に傾く。