
Fastify review
Node.js web framework with JSON Schema validation, a plugin system and built-in Pino logging
Verdict
Fastify is a good fit for Node.js APIs that want schema validation, typed routes and OpenAPI docs from official plugins, with encapsulated plugins that keep larger codebases in order. The catch is that the schema-first style and plugin encapsulation take some learning, and the project published many security advisories in the last year, mostly validation bypasses, so teams need to keep up with patch releases.
Best for
Teams building JSON APIs on Node.js that want validation and OpenAPI docs from one project
Not for
Teams that need Bun, Deno or edge runtimes, or want a full MVC framework with an ORM
Pros
- Request validation and response serialisation from JSON Schema in the core
- Official plugins for OpenAPI, WebSockets, JWT, OAuth2 and rate limits
- Ships its own types, with type providers that type routes from schemas
- Published support policy for each major version
Cons
- Many security advisories in the last year, most about validation
- Plugin encapsulation and schemas take time to learn
- Node.js only, with no official Bun, Deno or Workers support
Is Fastify right for your project?
Describe what you need and AI will check the fit against this review.
Fastify features and capabilities
Schema validation and serialisation
Route schemas validate bodies, params, queries and headers and also speed up JSON output, so one schema covers input checks and response shape.
OpenAPI from routes
The official @fastify/swagger plugin builds an OpenAPI document from route schemas, and @fastify/swagger-ui serves it, so docs stay in step with the code.
Encapsulated plugins
Each plugin gets its own scope for routes, hooks and decorators, which lets teams split a large API into parts that cannot leak into each other.
Built-in logging
Turning on the Pino logger gives each request its own logger and an id, so structured request logs need no extra package.
Official auth plugins
JWT, OAuth2, sessions, basic and bearer auth come from the Fastify org, and @fastify/auth combines them per route.
- TypeScript firstWritten in TypeScript or ships its own types, with typed routes or handlers
- YesShips types; type providers type routes from schemas
- Request validationValidates bodies, params or queries against a schema, in the core or an official package
- YesJSON Schema in the core
- OpenAPI docsGenerates an OpenAPI spec or Swagger UI from routes
- YesOfficial @fastify/swagger plugin
- Beyond Node.jsOfficially runs on Bun, Deno or edge runtimes such as Cloudflare Workers
- NoNode.js only; AWS Lambda via @fastify/aws-lambda
- WebSocketsBuilt in or through an official plugin
- YesOfficial @fastify/websocket plugin
- Project structureModules, dependency injection or a fixed layout, not only routing
- PartlyEncapsulated plugins, autoload and awilix DI; no fixed layout
- Database layerAn official ORM, query builder or data layer
- PartlyOfficial connection plugins, no ORM
- AuthenticationAn official auth module, plugin or strategy system
- YesOfficial @fastify/auth, @fastify/jwt and @fastify/oauth2
At a glance
- Type
- Web framework
- Stack
- JavaScript / Node.js 20+
- Databases
- PostgreSQL, MySQL, MongoDB, Redis
Free vs paid editions
What you get when you self-host, and what needs a paid plan.
Fastify and its official plugins are free and have no paid edition or official hosting. It is an OpenJS Foundation project.
Running Fastify
Fastify 5 needs Node.js 20 or later, and TypeScript projects also install @types/node.
New cloud server to ready
4 s
Memory in use at idle
78 MB of 4 GB
Reads per second
19,918
Writes per second
12,288
Startup
0.44 s
Version tested
5.12.7 · Oct 31, 2026
- The JSON Schema on the route did the validation, with no other dependency: 48 packages and 15 MB installed.
- Reads had a median latency of 2.4 ms and 4.4 ms at the 99th percentile, the lowest of the seven.
- By default the error names only the first invalid field. The price was also wrong, but only the name was reported.
import Fastify from "fastify";
// 100 items kept in memory, so the test measures the framework, not a database.
const items = new Map();
for (let i = 1; i <= 100; i++) items.set(i, { id: i, name: `Item ${i}`, price: i * 1.5, tags: ["sample"] });
let nextId = 101;
const app = Fastify();
app.get("/health", async () => ({ status: "ok" }));
app.get("/items/:id", async (req, reply) => {
const item = items.get(Number(req.params.id));
if (!item) return reply.code(404).send({ error: "Not found" });
return item;
});
app.post("/items", {
schema: {
body: {
type: "object",
required: ["name", "price"],
additionalProperties: false,
properties: {
name: { type: "string", minLength: 1, maxLength: 100 },
price: { type: "number", minimum: 0 },
tags: { type: "array", items: { type: "string" }, maxItems: 10 },
},
},
},
}, async (req, reply) => {
const item = { id: nextId++, ...req.body };
items.set(item.id, item);
return reply.code(201).send(item);
});
await app.listen({ port: Number(process.env.PORT ?? 3000), host: "127.0.0.1" });{
"statusCode": 400,
"code": "FST_ERR_VALIDATION",
"error": "Bad Request",
"message": "body/name must NOT have fewer than 1 characters"
}What you can do with Fastify
Public JSON APIs with docs
Define each route with a schema and publish an OpenAPI document and Swagger UI from the same definitions.
Microservices on Node.js
Split services into encapsulated plugins with their own hooks, logging and database clients.
Real-time endpoints
Add WebSocket or server-sent event routes next to REST routes with the official @fastify/websocket and @fastify/sse plugins.