0PricingLogin
NestJS Enterprise Backend APIs · Lesson

Dynamic Provider Registration with DiscoveryService

Scan and wire providers at runtime using DiscoveryService and MetadataScanner for plugin systems.

The Plugin Wiring Problem

In a plugin architecture, you don't know at compile time which handlers, strategies, or adapters will exist. A hexagonal core defines ports; plugins supply adapters. The challenge: how does the framework find and wire those adapters without you hand-registering each one?

  • Hard-coded arrays in a module are brittle — every new plugin edits core code.
  • You want providers to self-declare their role via decorators, then be discovered at runtime.

NestJS ships @nestjs/core's DiscoveryService and MetadataScanner exactly for this. They let you scan the live DI container and react to metadata.

Marking Providers with a Decorator

The pattern starts with a custom decorator that stamps metadata onto a class. We use SetMetadata (or Reflector.createDecorator) so the scanner can later filter for it.

Here a @Plugin() decorator tags a class as a discoverable plugin and carries a name so the registry can key on it.

import { SetMetadata } from '@nestjs/common';

export const PLUGIN_KEY = 'app:plugin';

export interface PluginMeta {
  name: string;
}

export const Plugin = (meta: PluginMeta): ClassDecorator =>
  SetMetadata(PLUGIN_KEY, meta);

// A plugin author writes:
@Plugin({ name: 'csv-exporter' })
export class CsvExporter {
  export(rows: unknown[]): string {
    return rows.map((r) => JSON.stringify(r)).join('\n');
  }
}

All lessons in this course

  1. Ports and Adapters for Domain Isolation
  2. Dynamic Provider Registration with DiscoveryService
  3. Lazy-Loaded Modules and Feature Toggles
  4. Extension Points with the Module Reference API
← Back to NestJS Enterprise Backend APIs