Foundations View as Markdown

Hello, World!

A running NestJS application in three commands, and what each generated file is actually for.

NestJS is a Node.js framework that gives a back end the thing Express deliberately does not: structure. Modules, dependency injection, decorators, and a strong convention for where everything goes.

That structure is why it is worth learning in 2026. A codebase where every piece has an obvious home is one you can review quickly — and reviewing is now most of the job.

Create the project#

shell
npm i -g @nestjs/cli
nest new hello-nest
cd hello-nest && npm run start:dev

Open http://localhost:3000. You will see Hello World!.

What was generated#

src/
  main.ts              entry point. creates the app, listens on a port.
  app.module.ts        the root module. wires everything together.
  app.controller.ts    handles HTTP requests. no business logic.
  app.service.ts       the logic. injected into the controller.
  app.controller.spec.ts

That four-file split is the whole mental model, and it repeats at every level of a Nest application.

The entry point#

src/main.ts
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 walks the module graph, constructs every provider, resolves every dependency, and hands you an application.

The controller#

src/app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}

Two things are happening that are easy to miss:

  1. @Controller() with no argument means this handles the root path. @Controller('users') would prefix every route in the class with /users.
  2. private readonly appService: AppService in the constructor is the whole dependency injection system. You never write new AppService(). Nest reads the type, finds the provider, and passes it in.

The service#

src/app.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}

@Injectable() marks the class as something Nest can construct and inject. Business logic lives here — not in the controller.

The module#

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

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

A module is a declaration of what belongs together. controllers handle requests; providers can be injected; exports makes a provider available to other modules that import this one.

Add a route#

src/app.controller.ts
@Get('health')
health(): { status: string; at: string } {
  return { status: 'ok', at: new Date().toISOString() };
}

http://localhost:3000/health now returns JSON. Nest serialises objects automatically and sets the content type.

Common questions#

Is NestJS just Angular for the back end?#

The decorator syntax and the dependency injection are deliberately Angular-like, and that is where the resemblance ends. Nest runs on Express or Fastify underneath and is a server framework throughout.

Do I need to know Express?#

No, but it helps when you need to drop down a level. Nest exposes the underlying request and response objects when you ask for them, and most Express middleware works unchanged.

Express or Fastify?#

Express is the default and has the larger middleware ecosystem. Fastify is faster and the adapter is a one-line change. Start on Express; switch if benchmarks ever tell you to.

Get the NestJS agent pack

A battle-tested AGENTS.md, the review checklist, and the failure-mode cheat sheet for NestJS. One email, then occasional updates when the tooling shifts. No course pitch.

Unsubscribe in one click. We never sell the list. Or just take the AGENTS.md now — no email needed.