--- id: wiki-2026-0508-fastify title: Fastify category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Fastify Framework, fastify.js] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [nodejs, web-framework, backend, performance] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: typescript framework: fastify-5 --- # Fastify ## 매 한 줄 > **"매 fastest Node.js web framework — schema-first, plugin-driven, zero-overhead"**. Fastify는 2016 Tomas Della Vedova 와 Matteo Collina 가 Express 의 throughput limit 을 깨고 schema-driven validation 을 native 로 만들기 위해 시작. 2026 현재 v5.x — Node 22 LTS, native fetch undici, Pino logging, async hooks 기반 plugin system 이 표준. ## 매 핵심 ### 매 설계 원칙 - **Schema-first**: 매 route 가 JSON Schema 의 declare — request/response validation + serialization 의 fast-json-stringify 통해 2-3x serialize speedup. - **Encapsulation**: 매 plugin 의 own scope — 매 child 가 parent 의 decorator 의 inherit 하되 sibling 의 isolated. - **Async/await native**: 매 handler 가 promise return — 매 reply.send() implicit. - **Zero-overhead logging**: Pino 의 default — 매 JSON structured, async write. ### 매 vs Express - 매 throughput: Fastify ~76k req/s vs Express ~13k req/s (Tech Empower 2026). - 매 type safety: TypeScript first-class — 매 FastifyInstance generic 의 typed plugin chain. - 매 ecosystem: 300+ official plugins (@fastify/*) — auth, cors, swagger, websocket, etc. ### 매 응용 1. High-throughput REST/JSON API gateway. 2. GraphQL server (Mercurius 통해). 3. Microservice 의 internal RPC. ## 💻 패턴 ### Server bootstrap with TypeBox schema ```typescript import Fastify from 'fastify'; import { TypeBoxTypeProvider, Type } from '@fastify/type-provider-typebox'; const app = Fastify({ logger: true }).withTypeProvider(); app.get('/users/:id', { schema: { params: Type.Object({ id: Type.String({ format: 'uuid' }) }), response: { 200: Type.Object({ id: Type.String(), name: Type.String() }), }, }, }, async (req) => { // req.params.id is typed as string return { id: req.params.id, name: 'Ada' }; }); await app.listen({ port: 3000, host: '0.0.0.0' }); ``` ### Encapsulated plugin ```typescript import fp from 'fastify-plugin'; export default fp(async (app) => { app.decorate('db', await connectPg(process.env.DATABASE_URL!)); app.addHook('onClose', async (instance) => instance.db.end()); }, { name: 'pg-plugin', dependencies: [] }); // Usage in route file app.register(async (scope) => { scope.get('/health', async (req) => { const r = await app.db.query('SELECT 1'); return { ok: r.rowCount === 1 }; }); }); ``` ### JWT auth with @fastify/jwt ```typescript import jwt from '@fastify/jwt'; app.register(jwt, { secret: process.env.JWT_SECRET! }); app.decorate('auth', async (req, reply) => { try { await req.jwtVerify(); } catch { reply.code(401).send({ error: 'unauthorized' }); } }); app.get('/me', { preHandler: app.auth }, async (req) => req.user); ``` ### Hooks lifecycle ```typescript app.addHook('onRequest', async (req) => { req.startTime = process.hrtime.bigint(); }); app.addHook('onResponse', async (req, reply) => { const elapsed = Number(process.hrtime.bigint() - req.startTime!) / 1e6; req.log.info({ url: req.url, elapsed_ms: elapsed }, 'request done'); }); ``` ### Streaming response ```typescript import { Readable } from 'node:stream'; app.get('/export.ndjson', async (req, reply) => { reply.type('application/x-ndjson'); const stream = Readable.from(generateRecords()); return stream; // Fastify pipes automatically }); async function* generateRecords() { for await (const row of db.query('SELECT * FROM events')) { yield JSON.stringify(row) + '\n'; } } ``` ### WebSocket plugin ```typescript import websocket from '@fastify/websocket'; app.register(websocket); app.register(async (scope) => { scope.get('/ws', { websocket: true }, (socket, req) => { socket.on('message', (msg) => { socket.send(`echo: ${msg}`); }); }); }); ``` ### Error handling ```typescript app.setErrorHandler((err, req, reply) => { if (err.validation) { reply.code(400).send({ error: 'validation', details: err.validation }); return; } req.log.error(err); reply.code(500).send({ error: 'internal' }); }); ``` ### Graceful shutdown ```typescript import closeWithGrace from 'close-with-grace'; closeWithGrace({ delay: 10_000 }, async ({ signal, err }) => { if (err) app.log.error(err); await app.close(); }); ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | High RPS JSON API | Fastify ✅ (default) | | Existing Express middleware ecosystem | Express + middie compat layer | | Type-safe schema-first | Fastify + TypeBox / Zod | | Edge runtime (Cloudflare Workers) | Hono (Fastify is Node-only) | | GraphQL | Fastify + Mercurius | **기본값**: Fastify v5 + TypeBox + Pino — 매 Node 22 LTS 위. ## 🔗 Graph - 부모: [[Node.js]] · [[HTTP-Server]] - 변형: [[Express]] · [[Hono]] · [[NestJS]] - 응용: [[REST-API]] · [[Microservices]] · [[API-Gateway]] - Adjacent: [[TypeBox]] · [[Pino]] · [[OpenAPI]] ## 🤖 LLM 활용 **언제**: schema-driven REST/JSON API, microservice, high-throughput gateway, structured logging required. **언제 X**: edge runtime (Workers/Deno Deploy) — Hono 의 use; full opinionated DI/DDD framework wanted — NestJS 의 use. ## ❌ 안티패턴 - **No schema**: route 의 schema-less 면 fast-json-stringify 의 benefit 의 lose — 매 always declare response schema. - **Sync handlers**: 매 use async — sync return 의 reply.send() forget 위험. - **Plugin without fastify-plugin**: encapsulation break 의 want 면 fp() wrap — 매 decorator parent 의 expose. - **Manual JSON.stringify**: 매 reply.send(obj) — fast-json-stringify 의 use. ## 🧪 검증 / 중복 - Verified (fastify.dev v5 docs, Tech Empower Round 22 2026). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — Fastify v5 patterns + TypeBox/Pino/WebSocket recipes |