Built-In For Day One, Pino For Production
Logging
Nest ships a Logger you can use immediately. For production, swap in nestjs-pino for fast structured JSON logs.
What you'll learn
- Inject Logger and use it from services
- Replace the default logger with a custom LoggerService
- Use nestjs-pino for structured logs in production
Out of the box, Nest gives you a Logger class with sensible defaults.
That is enough for development, but in production you want structured JSON,
correlation IDs, and predictable performance — which is where nestjs-pino
comes in.
The Built-In Logger
import { Injectable, Logger } from '@nestjs/common';
@Injectable()
export class OrdersService {
private readonly logger = new Logger(OrdersService.name);
create(dto: unknown) {
this.logger.log('Creating order');
this.logger.warn('Stock low');
this.logger.error('Failed to charge card', new Error().stack);
}
} The class name appears as the log context, which makes greppable logs a breeze.
Filtering Levels
In main.ts you can suppress noisy debug logs in production:
const app = await NestFactory.create(AppModule, {
logger: process.env.NODE_ENV === 'production'
? ['log', 'warn', 'error']
: ['log', 'warn', 'error', 'debug', 'verbose'],
}); Structured Logging With Pino
npm i nestjs-pino pino-http pino-pretty import { LoggerModule } from 'nestjs-pino';
@Module({
imports: [
LoggerModule.forRoot({
pinoHttp: {
level: process.env.LOG_LEVEL ?? 'info',
transport: process.env.NODE_ENV !== 'production'
? { target: 'pino-pretty' }
: undefined,
},
}),
],
})
export class AppModule {} Then in main.ts swap in the pino logger:
import { Logger } from 'nestjs-pino';
const app = await NestFactory.create(AppModule, { bufferLogs: true });
app.useLogger(app.get(Logger)); You now get one JSON line per request, automatic request IDs, and far lower CPU overhead than the default logger.
Caching →