Introducción a módulos dinámicos
Los módulos dinámicos en NestJS representan una evolución natural de los módulos estáticos que hemos visto anteriormente. Mientras que los módulos tradicionales tienen una configuración fija definida en tiempo de compilación, los módulos dinámicos permiten crear configuraciones flexibles que se determinan en tiempo de ejecución.
Esta capacidad resulta especialmente útil cuando necesitamos que un módulo se comporte de manera diferente según el entorno, la configuración del usuario, o parámetros específicos de la aplicación. Los módulos dinámicos son la base de muchas librerías populares del ecosistema NestJS, como @nestjs/config
, @nestjs/typeorm
y @nestjs/jwt
.
Diferencias fundamentales con módulos estáticos
Un módulo estático tradicional se define con una estructura fija:
@Module({
imports: [TypeOrmModule],
controllers: [UserController],
providers: [UserService],
exports: [UserService]
})
export class UserModule {}
En contraste, un módulo dinámico se crea mediante métodos estáticos que retornan un objeto DynamicModule
:
@Module({})
export class DatabaseModule {
static forRoot(options: DatabaseOptions): DynamicModule {
return {
module: DatabaseModule,
imports: [],
providers: [
{
provide: 'DATABASE_OPTIONS',
useValue: options,
},
DatabaseService,
],
exports: [DatabaseService],
};
}
}
Estructura de un módulo dinámico
La interfaz DynamicModule
extiende las propiedades de un módulo estático añadiendo la propiedad obligatoria module
:
interface DynamicModule {
module: Type<any>;
imports?: Array<Type<any> | DynamicModule | Promise<DynamicModule>>;
controllers?: Type<any>[];
providers?: Provider[];
exports?: Array<string | symbol | Type<any> | DynamicModule>;
global?: boolean;
}
La propiedad module
debe hacer referencia a la clase del módulo que está creando la configuración dinámica. Las demás propiedades funcionan igual que en los módulos estáticos, pero pueden ser calculadas dinámicamente.
Implementación básica de un módulo dinámico
Veamos cómo crear un módulo dinámico para gestionar configuraciones de base de datos:
import { Module, DynamicModule } from '@nestjs/common';
interface DatabaseConfig {
host: string;
port: number;
database: string;
username: string;
password: string;
}
@Module({})
export class ConfigurableModule {
static forRoot(config: DatabaseConfig): DynamicModule {
const providers = [
{
provide: 'DATABASE_CONFIG',
useValue: config,
},
{
provide: 'DATABASE_CONNECTION',
useFactory: (config: DatabaseConfig) => {
// Lógica para crear conexión basada en la configuración
return `Conectado a ${config.host}:${config.port}/${config.database}`;
},
inject: ['DATABASE_CONFIG'],
},
];
return {
module: ConfigurableModule,
providers,
exports: ['DATABASE_CONNECTION'],
};
}
}
Uso de módulos dinámicos
Para utilizar un módulo dinámico, lo importamos llamando a su método estático de configuración:
@Module({
imports: [
ConfigurableModule.forRoot({
host: 'localhost',
port: 5432,
database: 'myapp',
username: 'admin',
password: 'secret123'
})
],
controllers: [AppController],
})
export class AppModule {}
Esta flexibilidad permite que el mismo módulo se configure de manera diferente en distintos entornos:
// Configuración para desarrollo
ConfigurableModule.forRoot({
host: 'localhost',
port: 5432,
database: 'myapp_dev',
username: 'dev_user',
password: 'dev_pass'
})
// Configuración para producción
ConfigurableModule.forRoot({
host: 'prod-server.com',
port: 5432,
database: 'myapp_prod',
username: 'prod_user',
password: process.env.DB_PASSWORD
})
Patrones comunes de nomenclatura
Los módulos dinámicos suelen seguir patrones de nomenclatura específicos para sus métodos estáticos:
forRoot()
: Configuración global del módulo, típicamente usado en el módulo raíz de la aplicaciónforFeature()
: Configuración específica para características particulares, usado en módulos de funcionalidadregister()
: Configuración simple sin opciones asíncronasregisterAsync()
: Configuración asíncrona que permite inyección de dependencias
@Module({})
export class FeatureModule {
// Configuración síncrona
static register(options: FeatureOptions): DynamicModule {
return {
module: FeatureModule,
providers: [
{ provide: 'FEATURE_OPTIONS', useValue: options }
]
};
}
// Configuración asíncrona
static registerAsync(options: FeatureAsyncOptions): DynamicModule {
return {
module: FeatureModule,
imports: options.imports || [],
providers: [
{
provide: 'FEATURE_OPTIONS',
useFactory: options.useFactory,
inject: options.inject || []
}
]
};
}
}
Ventajas de los módulos dinámicos
Los módulos dinámicos ofrecen múltiples beneficios en el desarrollo de aplicaciones NestJS:
- Reutilización: Un mismo módulo puede servir diferentes propósitos según su configuración
- Flexibilidad: Permiten adaptar el comportamiento según el entorno o parámetros específicos
- Mantenibilidad: Centralizan la lógica de configuración en un solo lugar
- Escalabilidad: Facilitan la creación de librerías y paquetes configurables
Esta aproximación es fundamental para entender cómo funcionan internamente muchas de las librerías más utilizadas en el ecosistema NestJS, y proporciona las bases para crear nuestros propios módulos configurables y reutilizables.
Fuentes y referencias
Documentación oficial y recursos externos para profundizar en Nest
Documentación oficial de Nest
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Nest es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Nest
Explora más contenido relacionado con Nest y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
- Comprender la diferencia entre módulos estáticos y dinámicos en NestJS.
- Aprender la estructura y propiedades de un módulo dinámico.
- Implementar un módulo dinámico básico con configuración personalizada.
- Utilizar módulos dinámicos en diferentes entornos mediante métodos estáticos.
- Conocer patrones comunes de nomenclatura y ventajas de los módulos dinámicos.