fastify-best-practices
npx skills add https://github.com/jgamaraalv/ts-dev-kit --skill fastify-best-practices
Agent 安装分布
Skill 文档
Fastify 5 Best Practices
Table of Contents
Request lifecycle (exact order)
Incoming Request
ââ Routing
ââ onRequest hooks
ââ preParsing hooks
ââ Content-Type Parsing
ââ preValidation hooks
ââ Schema Validation (â 400 on failure)
ââ preHandler hooks
ââ Route Handler
ââ preSerialization hooks
ââ onSend hooks
ââ Response Sent
ââ onResponse hooks
Error at any stage â onError hooks â error handler â onSend â response â onResponse.
Top anti-patterns
-
Mixing async/callback in handlers â Use
asyncOR callbacks, never both. With async,returnthe value; don’t callreply.send()AND return. -
Returning
undefinedfrom async handler â Fastify treats this as “no response yet”. Return the data or callreply.send(). -
Using arrow functions when you need
thisâ Arrow functions don’t bindthisto the Fastify instance. Usefunctiondeclarations for handlers that needthis. -
Forgetting
fastify-pluginwrapper â Without it, decorators/hooks stay scoped to the child context. Parent and sibling plugins won’t see them. -
Decorating with reference types directly â
decorateRequest('data', {})shares the SAME object across all requests. Usenullinitial +onRequesthook to assign per-request. -
Sending response in
onErrorhook âonErroris read-only for logging. UsesetErrorHandler()to modify error responses. -
Not handling
reply.send()in async hooks â Callreturn replyafterreply.send()in async hooks to prevent “Reply already sent” errors. -
Ignoring encapsulation â Decorators/hooks registered in child plugins are invisible to parents. Design your plugin tree carefully.
-
String concatenation in SQL from route params â Always use parameterized queries. Fastify validates input shape, not content safety.
-
Missing response schema â Without
responseschema, Fastify serializes withJSON.stringify()(slow) and may leak sensitive fields. Usefast-json-stringifyvia response schemas.
Quick patterns
Plugin with fastify-plugin (FastifyPluginCallback)
Project convention: use FastifyPluginCallback + done() (avoids require-await lint errors).
import fp from "fastify-plugin";
import type { FastifyPluginCallback } from "fastify";
const myPlugin: FastifyPluginCallback = (fastify, opts, done) => {
fastify.decorate("myService", new MyService());
done();
};
export default fp(myPlugin, { name: "my-plugin" });
Route with validation
fastify.post<{ Body: CreateUserBody }>("/users", {
schema: {
body: {
type: "object",
required: ["email", "name"],
properties: {
email: { type: "string", format: "email" },
name: { type: "string", minLength: 1 },
},
},
response: {
201: {
type: "object",
properties: {
id: { type: "string" },
email: { type: "string" },
},
},
},
},
handler: async (request, reply) => {
const user = await createUser(request.body);
return reply.code(201).send(user);
},
});
Hook (application-level)
fastify.addHook("onRequest", async (request, reply) => {
request.startTime = Date.now();
});
fastify.addHook("onResponse", async (request, reply) => {
request.log.info({ elapsed: Date.now() - request.startTime }, "request completed");
});
Error handler
fastify.setErrorHandler((error, request, reply) => {
request.log.error(error);
const statusCode = error.statusCode ?? 500;
reply.code(statusCode).send({
error: statusCode >= 500 ? "Internal Server Error" : error.message,
});
});
Reference files
Load the relevant file when you need detailed API information:
- Server factory & options â constructor options, server methods, properties: references/server-and-options.md
- Routes & handlers â declaration, URL params, async patterns, constraints: references/routes-and-handlers.md
- Hooks & lifecycle â all 16 hook types, signatures, scope, early response: references/hooks-and-lifecycle.md
- Plugins & encapsulation â creating plugins, fastify-plugin, context inheritance: references/plugins-and-encapsulation.md
- Validation & serialization â JSON Schema, Ajv, response schemas, custom validators: references/validation-and-serialization.md
- Request, Reply & errors â request/reply API, error handling, FST_ERR codes: references/request-reply-errors.md
- TypeScript & logging â route generics, type providers, Pino config, decorators: references/typescript-and-logging.md