A dynamic module returns a DynamicModule object from a static method (conventionally forRoot(), forFeature(), or register()) so the caller can pass configuration at import time. Use it for library modules like config, TypeORM, or mailer where behavior must vary per consumer.
Dynamic modules allow you to create customizable modules whose providers are determined at import time, based on options passed by the consuming module.
forRoot() — used once at the app level with global configuration.
forFeature() — used in feature modules with feature-specific config (e.g., TypeORM entities).
register() — general-purpose configuration, used in any module.
We need to add a third‑party logging service that requires an API key at startup. How would you expose that service using a dynamic module?
If you import a module that offers a forRoot method but you forget to call it, what will happen when you try to inject its service?
You have a feature flag that should enable a payment provider only in production. Walk me through how you’d use a dynamic module to conditionally register that provider.
During debugging you see an error that a provider from a dynamic module isn’t being injected. What are the common reasons for this failure?
Design a multi‑tenant SaaS where each tenant gets its own database connection. Explain how you’d structure the connection module as a dynamic module and discuss any trade‑offs.
If you end up loading dozens of dynamic modules at runtime, what performance or memory concerns arise and how would you mitigate them?
Your organization wants to share a common authentication library across several microservices owned by different teams. How would you package it as a dynamic module to support versioning, backward compatibility, and independent deployment?
Consider a scenario where the same dynamic module needs to be used by both NestJS and a plain Node.js service. What architectural decisions would you make to keep the module reusable while preserving testability?