Skip to content

NestJS Day 1: Basic Walkthrough

NestJS Day 1

Abstract

This is a concise, summarized approach to learn NestJS. For more in-depth knowledge about NestJS, visit the official NestJS documentation.

Youtube video

Github repo for day 1

Nest CLI

Before creating a new NestJS project, you need to install the NestJS CLI globally. You can do this by running the following command:

Terminal window
npm install -g @nestjs/cli

To see a list of available commands, run the following command:

Terminal window
nest --help

Output:

Terminal window
Usage: nest <command> [options]
Options:
-v, --version Output the current version.
-h, --help Output usage information.
Commands:
new|n [options] [name] Generate Nest application.
build [options] [app] Build Nest application.
start [options] [app] Run Nest application.
info|i Display Nest project details.
add [options] <library> Adds support for an external library to your project.
generate|g [options] <schematic> [name] [path] Generate a Nest element.
Schematics available on @nestjs/schematics collection:
┌───────────────┬─────────────┬──────────────────────────────────────────────┐
name alias description
application application Generate a new application workspace
class cl Generate a new class
configuration config Generate a CLI configuration file
controller co Generate a controller declaration
decorator d Generate a custom decorator
filter f Generate a filter declaration
gateway ga Generate a gateway declaration
guard gu Generate a guard declaration
interceptor itc Generate an interceptor declaration
interface itf Generate an interface
middleware mi Generate a middleware declaration
module mo Generate a module declaration
pipe pi Generate a pipe declaration
provider pr Generate a provider declaration
resolver r Generate a GraphQL resolver declaration
service s Generate a service declaration
library lib Generate a new library within a monorepo
sub-app app Generate a new application within a monorepo
resource res Generate a new CRUD resource
└───────────────┴─────────────┴──────────────────────────────────────────────┘

To know more about a specific command, run the following command:

Terminal window
nest <command> --help

Example, nest generate --help.

Output:

Terminal window
Usage: nest generate|g [options] <schematic> [name] [path]
Generate a Nest element.
Schematics available on @nestjs/schematics collection:
┌───────────────┬─────────────┬──────────────────────────────────────────────┐
name alias description
application application Generate a new application workspace
class cl Generate a new class
configuration config Generate a CLI configuration file
controller co Generate a controller declaration
decorator d Generate a custom decorator
filter f Generate a filter declaration
gateway ga Generate a gateway declaration
guard gu Generate a guard declaration
interceptor itc Generate an interceptor declaration
interface itf Generate an interface
middleware mi Generate a middleware declaration
module mo Generate a module declaration
pipe pi Generate a pipe declaration
provider pr Generate a provider declaration
resolver r Generate a GraphQL resolver declaration
service s Generate a service declaration
library lib Generate a new library within a monorepo
sub-app app Generate a new application within a monorepo
resource res Generate a new CRUD resource
└───────────────┴─────────────┴──────────────────────────────────────────────┘
Options:
-d, --dry-run Report actions that would be taken without writing out results.
-p, --project [project] Project in which to generate files.
--flat Enforce flat structure of generated element.
--no-flat Enforce that directories are generated.
--spec Enforce spec files generation. (default: true)
--skip-import Skip importing (default: false)
--no-spec Disable spec files generation.
-c, --collection [collectionName] Schematics collection to use.
-h, --help Output usage information.

To Learn more about CLI, visit official CLI doc.

Create & Running a Project

Run the following command to create a project,

Terminal window
nest new <project-name>

Then select a package manager, I am going to select pnpm. I’ve ran nest new shamscorner-nestjs command. My project name is shamscorner-nestjs. If you run the exact command, you should see the following output:

Terminal window
We will scaffold your app in a few seconds..
? Which package manager would you ❤️ to use? pnpm
CREATE shamscorner-nestjs/.eslintrc.js (663 bytes)
CREATE shamscorner-nestjs/.prettierrc (51 bytes)
CREATE shamscorner-nestjs/README.md (3347 bytes)
CREATE shamscorner-nestjs/nest-cli.json (171 bytes)
CREATE shamscorner-nestjs/package.json (1949 bytes)
CREATE shamscorner-nestjs/tsconfig.build.json (97 bytes)
CREATE shamscorner-nestjs/tsconfig.json (546 bytes)
CREATE shamscorner-nestjs/src/app.controller.spec.ts (617 bytes)
CREATE shamscorner-nestjs/src/app.controller.ts (274 bytes)
CREATE shamscorner-nestjs/src/app.module.ts (249 bytes)
CREATE shamscorner-nestjs/src/app.service.ts (142 bytes)
CREATE shamscorner-nestjs/src/main.ts (208 bytes)
CREATE shamscorner-nestjs/test/app.e2e-spec.ts (630 bytes)
CREATE shamscorner-nestjs/test/jest-e2e.json (183 bytes)
Installation in progress...
🚀 Successfully created project shamscorner-nestjs
👉 Get started with the following commands:
$ cd shamscorner-nestjs
$ pnpm run start
Thanks for installing Nest 🙏
Please consider donating to our open collective
to help us maintain this package.
🍷 Donate: https://opencollective.com/nest

Now, let’s navigate to the project directory and run the project.

Terminal window
cd shamscorner-nestjs
pnpm run start

If I open http://localhost:3000, I should see the hello world text. Awesome!

Language & Support

  • Both TypeScript and JavaScript are supported in NestJS.
  • TypeScript is the recommended language for NestJS.
  • Node.js (version >= 20)
  • Nest is platform agnostic
  • Platforms supported out-of-the-box: Express and Fastify

Project overview

Markdown table

FileDescription
src/app.controller.tsA basic controller that returns a hello world message.
src/app.controller.spec.tsA test file for the app controller.
src/app.module.tsThe root module of the application.
src/app.service.tsA basic service that returns a hello world message.
src/main.tsThe entry file of the application.

Let’s breakdown each file and understand what it does.

The src/main.ts file is the entry point of the application. It creates a new NestJS application instance and starts the HTTP server on port 3000.

src/main.ts
import { NestFactory } from "@nestjs/core";
// Import the root AppModule that defines the application structure and components
import { AppModule } from "./app.module";
// Define an asynchronous bootstrap function to initialize the application
async function bootstrap() {
// Create a new NestJS application instance with AppModule as the root module
const app = await NestFactory.create(AppModule);
// Start the HTTP server on port 3000
await app.listen(3000);
}
// Execute the bootstrap function to start the application
bootstrap();

The src/app.module.ts file is the root module of the application. It defines the application structure by importing and declaring other modules, controllers, and services.

src/app.module.ts
import { Module } from "@nestjs/common";
// Import the AppController which handles incoming requests
import { AppController } from "./app.controller";
// Import the AppService which contains the business logic
import { AppService } from "./app.service";
// @Module decorator to define this class as a NestJS module
@Module({
imports: [], // List of imported modules that export providers needed in this module
controllers: [AppController], // List of controllers defined in this module
providers: [AppService], // List of providers (services) that can be injected in this module
})
export class AppModule {} // Export the AppModule class to be used in the bootstrap file

The src/app.service.ts file is a basic service that returns a hello world message and responsible for the business logic.

src/app.service.ts
import { Injectable } from "@nestjs/common";
// @Injectable decorator indicates this class can be managed by NestJS dependency injection system
@Injectable()
export class AppService {
// Method that returns a simple string greeting
// The ': string' indicates this function returns a string value
getHello(): string {
// Return a "Hello World!" message when this method is called
return "Hello World!";
}
}

The src/app.controller.ts file is a basic controller that returns a hello world message. It delegates the business logic to the AppService.

src/app.controller.ts
import { Controller, Get } from "@nestjs/common";
// Import the AppService from a local file
// This service will contain the business logic
import { AppService } from "./app.service";
// @Controller() decorator marks this class as a NestJS controller
// Empty parentheses mean this controller handles requests to the root route '/'
// You could specify a path like @Controller('users') to handle '/users' routes
@Controller()
export class AppController {
// Constructor with dependency injection
// 'private readonly' makes appService a private, immutable property of the class
// NestJS will automatically inject an instance of AppService here
constructor(private readonly appService: AppService) {}
// @Get() decorator marks this method as a handler for GET requests
// Empty parentheses mean it handles the root path of this controller
// Combined with the controller's path, this handles GET requests to '/'
@Get()
// Method declaration with TypeScript return type annotation (string)
// This method will be called when a GET request is made to the root route
getHello(): string {
// The controller delegates the business logic to the service
// This maintains separation of concerns - controllers handle HTTP,
// while services handle business logic
return this.appService.getHello();
}
}

Finally, the src/app.controller.spec.ts file is a test file for the AppController. It uses Jest to test the controller’s behavior.

src/app.controller.spec.ts
import { Test, TestingModule } from "@nestjs/testing";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
// Main test suite for AppController
describe("AppController", () => {
// Declare a variable to hold the controller instance
let appController: AppController;
// Before each test, set up a testing module
beforeEach(async () => {
// Create a testing module that mimics the actual application module
const app: TestingModule = await Test.createTestingModule({
controllers: [AppController], // Register the controller to test
providers: [AppService], // Register the service dependencies
}).compile(); // Compile the module
// Get an instance of the controller from the testing module
appController = app.get<AppController>(AppController);
});
// Nested test suite focusing on the root endpoint
describe("root", () => {
// Individual test case checking if getHello returns the expected string
it('should return "Hello World!"', () => {
// Assert that the controller's getHello method returns "Hello World!"
expect(appController.getHello()).toBe("Hello World!");
});
});
});

Development mode

To run the application in development mode, use the following command. This will start the application in watch mode, which means the server will automatically reload when you make changes to the code.

Terminal window
pnpm run start:dev

Linting

To lint the application code, use the following command. This will check the code for any linting errors and provide suggestions for fixing them.

pnpm run lint