What are lifecycle hooks in NestJS?
Lifecycle Hooks in NestJS
NestJS provides lifecycle hooks that allow you to execute code at specific points during the application's startup and shutdown sequence. These are essential for initializing connections, starting background tasks, and graceful shutdown.
Available Hooks
| Hook Interface | Method | When Called |
|---|---|---|
OnModuleInit | onModuleInit() | After module's providers are initialized |
OnApplicationBootstrap | onApplicationBootstrap() | After all modules initialized, before listening |
OnModuleDestroy | onModuleDestroy() | After app.close() is called |
BeforeApplicationShutdown | beforeApplicationShutdown(signal) | Before shutdown (receives OS signal) |
OnApplicationShutdown | onApplicationShutdown(signal) | After all connections closed |
OnModuleInit — Setup after DI
typescript
import { Injectable, OnModuleInit } from '@nestjs/common';
@Injectable()
export class DatabaseService implements OnModuleInit {
async onModuleInit() {
// Called once after all providers in the module are instantiated
await this.connect();
console.log('Database connected');
}
private async connect() {
// Establish database connection
}
}OnApplicationBootstrap — After Full Init
typescript
import { Injectable, OnApplicationBootstrap } from '@nestjs/common';
@Injectable()
export class SeedService implements OnApplicationBootstrap {
constructor(
private readonly usersService: UsersService,
private readonly configService: ConfigService,
) {}
async onApplicationBootstrap() {
if (this.configService.get('NODE_ENV') === 'development') {
await this.seedDatabase();
}
}
private async seedDatabase() {
const count = await this.usersService.count();
if (count === 0) {
await this.usersService.create({ name: 'Admin', email: 'admin@app.com' });
console.log('Database seeded');
}
}
}Graceful Shutdown
typescript
// main.ts — enable shutdown hooks
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableShutdownHooks(); // listen for SIGTERM, SIGINT
await app.listen(3000);
}typescript
// services/queue.service.ts
import { Injectable, OnApplicationShutdown, BeforeApplicationShutdown } from '@nestjs/common';
@Injectable()
export class QueueService implements BeforeApplicationShutdown, OnApplicationShutdown {
private isShuttingDown = false;
beforeApplicationShutdown(signal: string) {
console.log(`Received signal: ${signal}`);
this.isShuttingDown = true;
// stop accepting new jobs
}
async onApplicationShutdown(signal: string) {
await this.waitForActiveJobs();
await this.closeConnection();
console.log('Queue service shut down gracefully');
}
private waitForActiveJobs(): Promise<void> {
return new Promise(resolve => setTimeout(resolve, 2000));
}
}OnModuleDestroy — Per-Module Cleanup
typescript
@Injectable()
export class CacheService implements OnModuleDestroy {
private client: RedisClient;
async onModuleDestroy() {
await this.client.quit();
console.log('Redis connection closed');
}
}Full Lifecycle Order
1. Modules initialized (providers created)
2. onModuleInit() — per provider
3. onApplicationBootstrap() — per provider
4. app.listen() — server starts accepting requests
---
[SIGTERM / app.close()]
5. beforeApplicationShutdown(signal) — per provider
6. Server stops accepting new connections
7. onModuleDestroy() — per provider
8. onApplicationShutdown(signal) — per provider
9. Process exitsSummary
Lifecycle hooks make NestJS services aware of the application lifecycle. Use OnModuleInit for post-DI setup (DB connections, cache warm-up), OnApplicationBootstrap for post-startup tasks (seeding, health checks), and OnApplicationShutdown + app.enableShutdownHooks() for graceful shutdown (draining connections, finishing jobs).
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.