title: 'Lifecycle events · Nael Framework' description: 'Use OnModuleInit, OnModuleDestroy, and bootstrap hooks to manage resources cleanly in Nael modules.'

Fundamentals

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.

Connect to Redis during bootstrap
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.

Disconnect from Kafka when exiting
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.

Bootstrap metrics collectors
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.

Graceful shutdown for HTTP
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 onModuleInit with a corresponding release in onModuleDestroy.