Plugin System
const fp = require('fastify-plugin');\n\n// Plugin definition\nasync function myPlugin(fastify, opts) {\n fastify.decorate('utility', {\n greet: (name) => `Hello, ${name}!`,\n });\n\n fastify.get('/plugin-route', async () => {\n return { message: fastify.utility.greet('Plugin') };\n });\n}\n\n// Wrap with fastify-plugin to break encapsulation\nmodule.exports = fp(myPlugin, {\n name: 'my-plugin',\n dependencies: ['@fastify/sensible'],\n});\n\n// Register the plugin\napp.register(require('./my-plugin'), {\n prefix: '/api',\n});
Encapsulation
Fastify plugins have full encapsulation. Decorators and hooks registered in a parent plugin are not visible to sibling plugins. Use the fastify-plugin wrapper to break encapsulation when needed.
// Context hierarchy:\n// Root (app)\n// └── Plugin A\n// └── Plugin A1 (child, can access A)\n// └── Plugin B (sibling, cannot access A)\n\n// Use fastify-plugin to share across siblings\nconst sharedPlugin = fp(async (fastify) => {\n fastify.decorate('shared', { value: 'accessible everywhere' });\n});
Examples
const Fastify = require('fastify');
const fp = require('fastify-plugin');
const app = Fastify({ logger: true });
// Plugin: adds a utility function
const utilsPlugin = fp(async (fastify) => {
fastify.decorate('utils', {
formatDate: (date) => date.toISOString().split('T')[0],
capitalize: (str) => str.charAt(0).toUpperCase() + str.slice(1),
});
fastify.decorateRequest('requestId', null);
fastify.addHook('onRequest', async (request) => {
request.requestId = Math.random().toString(36).slice(2, 10);
});
}, { name: 'utils' });
// Plugin: authentication
const authPlugin = fp(async (fastify) => {
fastify.decorate('authenticate', async (request, reply) => {
const token = request.headers.authorization?.split(' ')[1];
if (!token) {
reply.code(401).send({ error: 'Missing token' });
return;
}
request.user = { id: 1, role: 'user' };
});
}, { name: 'auth', dependencies: ['utils'] });
// Register plugins
app.register(utilsPlugin);
app.register(authPlugin);
app.get('/protected', {
preHandler: [app.authenticate],
}, async (request) => ({
message: 'Protected route',
user: request.user,
requestId: request.requestId,
}));
app.listen({ port: 3000 });