Fastify 5 web application conventions — plugin encapsulation, route schemas, validation, hooks lifecycle, error handling, TypeScript type providers, and testing patterns. Use when writing or modifying Fastify routes, plugins, decorators, hooks, or server setup code.
Apply these conventions when working with Fastify code in node.js projects.
logger: true (or Pino config object), trustProxy when behind a reverse proxy.app.ts) from server startup (server.ts / cluster.ts) to enable testing via inject() without starting the server.fastify.register(plugin, options).fastify-plugin wrapper only when a plugin must expose decorators or hooks to the parent scope (e.g., database connection, authentication decorator).dependencies array to fail fast at boot, not at runtime.fastify.get(), fastify.post(), etc.async handlers that return the response body. Do not mix return with reply.send() — pick one.prefix via register options.schema for request validation (body, querystring, params, headers) and response serialization (response).body, querystring, params, and response.fastify.addSchema({ $id, ... }) and reference via $ref.response schemas — they enable fast-json-stringify for serialization performance and prevent accidental leaking of internal fields.removeAdditional: true, useDefaults: true, coerceTypes: 'array'. Be aware that coercion can interact unexpectedly with anyOf/nullable types.@fastify/type-provider-typebox or @fastify/type-provider-json-schema-to-ts) to derive request/reply types from route schemas automatically.declare module 'fastify' { interface FastifyInstance { ... } }).FastifyPluginAsync for async plugin types. Pass plugin options as a generic parameter.decorate for the Fastify instance, decorateRequest for request, decorateReply for reply.decorateRequest/decorateReply — they are shared across all requests. Use null as default and set the actual value in an onRequest hook.hasDecorator() / hasRequestDecorator() / hasReplyDecorator() before adding.onRequest → preParsing → preValidation → preHandler → handler → preSerialization → onSend → onResponse.onError runs when an error occurs (before the error handler). onTimeout fires on request timeout. onRequestAbort fires on client disconnect.onReady, onListen, onRoute, onRegister, preClose, onClose.done callback — just return or throw.reply.send() in a hook to short-circuit the lifecycle and skip subsequent hooks/handler.fastify.setErrorHandler(async (error, request, reply) => { ... }).Error instances, never primitives. Fastify's built-in errors use FST_ prefixed codes (e.g., FST_ERR_VALIDATION).error.validation (raw errors) and error.validationContext (body, params, query, headers).fastify.inject({ method, url, payload, headers }) for testing without network overhead — no need to call listen().fastify.close() after tests to clean up connections.inject, assert, close.response schemas on all routes for serialization speed.bodyLimit per route for large/small payloads instead of raising the global limit.disableRequestLogging: true on high-throughput routes where request logs are not needed.