fastifyadapters

Fastify's adapter is a plugin, not middleware

Fastify doesn't have a middleware chain in the Express sense — everything is a plugin, and plugins are encapsulated by default. rbac-fs/fastify respects that architecture instead of fighting it.

Registration

import Fastify from 'fastify';
import { rbacPlugin } from 'rbac-fs/fastify';

const app = Fastify();
await app.register(rbacPlugin, { rbac });

app.post(
  '/invoices/:id/approve',
  { config: { rbac: { resource: 'invoice', action: 'approve' } } },
  async (request) => ({ approved: request.params.id }),
);

Permission config lives in each route's config.rbac object — not a wrapper function around the handler like Express/Koa's rbacMiddleware. Fastify's own route-config mechanism is the natural place for this, and it means the check runs as an onRequest-style hook the plugin registers once, not per-route boilerplate.

The encapsulation rule that actually matters

Fastify plugins are encapsulated by default: a hook or decorator registered inside a sub-plugin (via fastify-plugin's opt-out, or a nested register() call) is invisible to sibling routes outside that sub-plugin's boundary. rbacPlugin is wrapped in fastify-plugin specifically so its onRequest hook attaches at the root instead of being trapped inside an encapsulation boundary — but that only works if *you* also register it at the root app, not inside your own sub-plugin.

// wrong — hook won't see routes registered outside this sub-plugin
app.register(async (instance) => {
  await instance.register(rbacPlugin, { rbac });
  instance.post('/invoices/:id/approve', { config: { rbac: {...} } }, handler);
});

// right — register at the root, routes anywhere in the app are covered
await app.register(rbacPlugin, { rbac });
app.post('/invoices/:id/approve', { config: { rbac: {...} } }, handler);

Get this wrong and the symptom isn't an error — it's routes that silently skip the permission check entirely, which is worse than a crash.

For a runnable walkthrough, see Tutorial: the Fastify plugin end to end.