Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Logging: the built-in Logger

A log is the messages a server writes about its work: startup, errors, important user actions. The log is where you look for the cause of a failure on a server that has no debugger. Instead of console.log(), NestJS code uses the built-in Logger class: it adds the time, the severity level and the name of the class the message came from.

Logger in a service

// src/posts/posts.service.ts
import { Injectable, Logger } from '@nestjs/common';
import { CreatePostDto } from './dto/create-post.dto';
 
@Injectable()
export class PostsService {
  private readonly logger = new Logger(PostsService.name);
 
  create(dto: CreatePostDto) {
    this.logger.log(`Creating post "${dto.title}"`);
    // ...saving to the database
  }
}

new Logger(PostsService.name) creates a logger with a context — the class name. Create a post, and the terminal shows a line:

[Nest] 12345  - 10/03/2026, 10:15:00 AM     LOG [PostsService] Creating post "Hello, Nest"

It contains the process id, the time, the level and the context. The context shows at once which class wrote the message.

Levels

MethodLevelUsed for
logger.fatal()fatalA failure after which work is impossible
logger.error()errorAn error; the request failed
logger.warn()warnA suspicious situation
logger.log()logA normal event
logger.debug()debugDetails for debugging
logger.verbose()verboseVery detailed information

An error is logged together with the stack trace so you can find the line where it happened:

// src/posts/posts.service.ts
try {
  await this.postsRepository.save(post);
} catch (error) {
  this.logger.error('Failed to save the post', error.stack);
  throw error;
}

Choosing levels

A production server does not need detailed messages. The levels that reach the log are set when the application is created:

// src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
 
async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    logger: process.env.NODE_ENV === 'production'
      ? ['fatal', 'error', 'warn', 'log']
      : ['fatal', 'error', 'warn', 'log', 'debug', 'verbose'],
  });
  await app.listen(process.env.PORT ?? 3000);
}
bootstrap();

During development every message is visible, and on the server everything except debug and verbose.

JSON logs

Log collection systems read JSON more easily. In NestJS 11 the built-in logger can output it by itself:

// src/main.ts
import { ConsoleLogger } from '@nestjs/common';
 
const app = await NestFactory.create(AppModule, {
  logger: new ConsoleLogger({ json: true }),
});

Each message becomes one JSON line with level, context, message and other fields.

Common mistake

People log the whole request body or the whole user object — and passwords, tokens and hashes end up there. Logs are often kept longer than the database and are accessible to more people. Log ids and short event descriptions, not user data.

Thanks for reading!

Donate to the site — we work hard for you.