Lesson 15 / 32

Encapsulation & Scope

Keep hooks, decorators and routes scoped inside plugins to build modular, conflict-free apps.

Plugin scope isolation

Plugins registered inside another plugin are scoped to that plugin. Decorators, hooks, and routes don't leak to sibling plugins.

Nested plugins

Create sub-apps by registering a plugin that registers child plugins.

// routes/v1.js
export default async function v1Routes(fastify, opts) {
  fastify.get('/health', async () => ({ version: '1' }));
}

// routes/v2.js
export default async function v2Routes(fastify, opts) {
  fastify.get('/health', async () => ({ version: '2' }));
}

// server.js
fastify.register(v1Routes, { prefix: '/v1' });
fastify.register(v2Routes, { prefix: '/v2' });
// GET /v1/health -> { version: '1' }
// GET /v2/health -> { version: '2' }

Decorators stay inside their plugin

Each register creates a child context.

  • decorate in the child is invisible to the parent.
  • Wrap with fastify-plugin if you want to share it upward.
const fastify = require('fastify')();

fastify.register(async (child) => {
  child.decorate('secret', 42);
  console.log('child', child.secret);
});

fastify.ready().then(() => {
  console.log('parent', fastify.secret);
});

Output:

child 42
parent undefined

Quick check

Quick check: How do you make a plugin's decorator visible to the parent instance?

  • Name the plugin `global`
  • Wrap it with `fastify-plugin`
  • Call `decorate` twice
Answer

Wrap it with `fastify-plugin` — `fastify-plugin` skips encapsulation so decorators and hooks apply to the parent.