Every Feature Is a Plugin
Plugins — Fastify's Composition Unit
A Fastify plugin is an async function registered on the app — it adds routes, hooks, decorators, or other plugins, all in its own scope.
What you'll learn
- Write a plugin as an async (app, opts) function
- Register it with app.register
- Pass options through to the plugin
In Fastify, everything composable is a plugin: routes, middleware, integrations, even your own features. A plugin is just an async function plus a register call.
A Minimal Plugin
// src/plugins/health.ts
import type { FastifyPluginAsync } from 'fastify';
const healthPlugin: FastifyPluginAsync = async (app, opts) => {
app.get('/healthz', async () => ({ ok: true }));
app.get('/readyz', async () => ({ ready: await db.isReady() }));
};
export default healthPlugin; (app, opts) is the standard signature. app is a child of the parent app — anything you
register on it inherits parent context but does not leak back (more on that in the encapsulation
lesson).
Registering
import healthPlugin from './plugins/health.js';
await app.register(healthPlugin, {
// anything you want — Fastify passes it as the second arg
intervalMs: 5_000,
}); Options Are Yours
type Opts = { intervalMs?: number };
const myPlugin: FastifyPluginAsync<Opts> = async (app, opts) => {
const interval = opts.intervalMs ?? 30_000;
app.log.info({ interval }, 'plugin booted');
}; Why Use Plugins for Everything
Plugins encapsulate routes, hooks, and decorators into reusable units, give you per-feature test boundaries (mount one plugin into a test app), and they compose — a billing plugin can register Stripe, webhook routes, and a CRON-runner under one name.
The fastify-plugin Wrapper →