Skip to content

NestJS Basics

Before building real routes and APIs, you need a working mental model of the pieces NestJS is made of. This lesson walks through modules, controllers, providers, and how a Nest application boots from a single entry file.

The Building Blocks of a Nest App

Every NestJS application has a root module, conventionally AppModule, that NestJS uses as the starting point for building the dependency graph. From there, feature modules group related controllers and providers together.

A minimal Nest app needs three files: a module (app.module.ts), a controller (app.controller.ts), and an entry file (main.ts) that creates and starts the application using NestFactory.

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

NestFactory.create() reads AppModule, resolves every controller and provider in its dependency graph, and returns an application instance you can configure and start with listen().

The Nest Application Lifecycle

main.ts
  -> NestFactory.create(AppModule)
       -> reads @Module() metadata
       -> builds the dependency injection container
       -> registers controllers and their routes
  -> app.listen(port)
  • AppModule is decorated with @Module() and lists its controllers and providers.
  • NestFactory inspects module metadata to construct the full dependency injection graph.
  • Controllers are only reachable once they are listed in a module's controllers array.
  • Providers must be listed in providers (or exported from an imported module) to be injectable.

Nest Basics Cheatsheet

The minimum pieces every Nest application starts with.

Piece Example Description
Entry file main.ts Bootstraps the app with NestFactory.create()
Root module AppModule Top-level @Module() describing the app
Controller @Controller('cats') Groups routes under a base path
Provider @Injectable() A class that can be injected as a dependency
Start server app.listen(3000) Starts the underlying HTTP server

Anatomy of the Root Module

The @Module() decorator accepts an object with four optional arrays: imports (other modules this module depends on), controllers (route handlers registered by this module), providers (injectable classes), and exports (providers this module makes available to others).

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

How This Differs From Plain Node.js

In a plain Express app you manually create the app object, register middleware, and wire dependencies by hand (often via manual imports or a DI library). In Nest, the framework itself reads your decorators and builds that wiring automatically, all you provide is metadata.

  • You never manually instantiate a controller with new, Nest's container does it.
  • Constructor parameters typed with an injectable class are resolved automatically.
  • The same class can be swapped for a mock in tests without changing consuming code.

Common Mistakes

  • Forgetting to register a new controller or provider in its module's arrays.
  • Creating circular dependencies between modules without using forwardRef().
  • Putting business logic directly in main.ts instead of inside providers and modules.
  • Not understanding that NestFactory.create() is asynchronous and must be awaited.

Key Takeaways

  • Every Nest app boots from main.ts via NestFactory.create(AppModule).
  • Modules declare which controllers and providers belong to them.
  • Controllers must be registered in a module's controllers array to receive requests.
  • Providers must be registered in providers (or exported/imported) to be injectable.

Pro Tip

Run nest new once and read through the four generated files (main.ts, app.module.ts, app.controller.ts, app.service.ts) top to bottom, that four-file skeleton is the mental model for every larger Nest project you'll build.