Lifecycle events
Providers in Nael can perform setup and teardown logic through lifecycle interfaces. Knowing when these callbacks fire keeps long-lived connections healthy, prevents resource leaks, and allows modules to prepare caches before the first request hits.
OnModuleInit
Implement OnModuleInit to run code immediately after the container creates your provider. This is ideal for establishing database
connections, warming caches, or scheduling background tasks that should start only once.
import { Injectable, OnModuleInit } from '@nl-framework/core';import { createClient } from 'redis';@Injectable()export class CacheService implements OnModuleInit {private client = createClient({ url: process.env.REDIS_URL });async onModuleInit() {await this.client.connect();}async get(key: string) {return this.client.get(key);}}The container awaits the promise returned by onModuleInit, so make sure long-running work (migrations, hydration) remains bounded
to avoid delaying the entire application.
OnModuleDestroy
Implement OnModuleDestroy to release external resources during shutdown. The container calls every registered handler as part of
ApplicationContext.close() and platform close() methods.
import { Injectable, OnModuleDestroy } from '@nl-framework/core';import { Kafka } from 'kafkajs';@Injectable()export class EventBus implements OnModuleDestroy {private readonly kafka = new Kafka({ clientId: 'app', brokers: ['localhost:9092'] });private producer = this.kafka.producer();async onModuleInit() {await this.producer.connect();}async onModuleDestroy() {await this.producer.disconnect();}}Always wrap network cleanup in try/catch to log failures—shutdown should not crash the process.
Eager bootstrap providers
Modules can force specific providers to instantiate during startup via the bootstrap array in @Module metadata.
This is useful when the provider exposes a background loop or needs to populate shared state before handling traffic.
import { Module, Provider } from '@nl-framework/core';@Module({providers: [CacheService, StatsService],bootstrap: [CacheService],})export class MetricsModule {}Bootstrapped providers still receive onModuleInit callbacks; the array merely guarantees they are resolved eagerly.
Finishing up with platform close()
HTTP and GraphQL applications expose close() methods that call the underlying ApplicationContext.close(). Invoke
them during process shutdown signals so OnModuleDestroy handlers run and servers stop accepting connections gracefully.
import { createHttpApplication } from '@nl-framework/http';const app = await createHttpApplication(AppModule, { port: 3000 });const server = await app.listen();process.on('SIGTERM', async () => {await app.close();process.exit(0);});Best practices
- Keep lifecycle methods idempotent; Nael might instantiate providers more than once in transient or manual contexts.
- Log lifecycle failures with enough context to troubleshoot (module name, target service, external host).
- Pair every resource acquired in
onModuleInitwith a corresponding release inonModuleDestroy.