Building Your First REST API with NestJS: From Zero to Hero
From an empty terminal to a working custom endpoint: installing the Nest CLI, reading the generated project, and how the controller and service split the work between them.

Ever heard of NestJS and wondered why so many developers, especially from the Node.js world, are flocking to it? In short, NestJS brings structure and order to backend development with TypeScript. If you’re looking to get started, this article is your step-by-step guide to building your very first REST API.
We’ll go from installation all the way to creating our own custom endpoint. Let’s dive right in!
One note before we start: this guide targets NestJS 12, the current release line (published August 2026). The decorators and CLI commands below are unchanged from earlier versions — the Node.js requirement is the part that moved.
Why NestJS?
Before we start coding, it’s good to know what makes NestJS so special:
- Clear Structure: NestJS “forces” us to use a modular and organized architecture (heavily inspired by Angular). This makes projects easier to maintain and scale.
- TypeScript-first: Built entirely with TypeScript, it gives us benefits like static typing, autocompletion, and safer code.
- Powerful & Flexible: Under the hood, NestJS uses battle-tested HTTP frameworks like Express (the default) or Fastify. So, you get a rich ecosystem while enjoying the NestJS architecture.
Enough with the introductions, let’s get our tools ready!
✅ Prerequisites
Make sure you have these things installed on your computer:
- Node.js: Version 20.11 or newer — that is what the NestJS 12 CLI requires, and Node 16 and 18 are both past end-of-life. Check yours with node -v.
- NPM or Yarn: The package manager that comes with Node.js.
- Code Editor: Visual Studio Code is highly recommended.
All set? Let’s install the NestJS CLI.
Step 1: Install the NestJS CLI
NestJS has a super helpful Command Line Interface (CLI) for quickly scaffolding projects, modules, controllers, and other components. Open your terminal and run this command:
npm install -g @nestjs/cliThe command above will install the NestJS CLI globally on your system.
Step 2: Create a New Project
Once the CLI is installed, creating a new project is a piece of cake. Navigate to your desired working directory, then run:
nest new my-first-apiThe CLI will ask you which package manager you’d like to use (npm, yarn, or pnpm). Choose one, and let the CLI work its magic creating the project structure for you.
Once it’s done, navigate into your project directory:
cd my-first-apiIf you open the project folder, you’ll see a structure like this:
src/
├── app.controller.spec.ts
├── app.controller.ts
├── app.module.ts
├── app.service.ts
└── main.ts- main.ts: The entry point of our application. This is where the NestJS server is initialized.
- app.module.ts: The root module that organizes the application's components.
- app.controller.ts: The route handler. It receives requests and returns responses.
- app.service.ts: The place for business logic.
Step 3: Run the Application
Without changing a single thing, we already have a runnable application. To run it in development mode (with hot-reload), use this command:
npm run start:devWait a moment, and you’ll see a log in the terminal indicating that the application is running, usually on port 3000.
Now, open your browser or Postman and access http://localhost:3000. You'll be greeted with the message: Hello World!
Congratulations! Your first API is up and running! 🎉
Step 4: Understanding the Workflow: Controller & Service
Where did that “Hello World!” come from? Let’s break down the flow.
- Request Comes In: When you access http://localhost:3000, a GET request is sent to the application.
- Controller Handles It: app.controller.ts handles this request. Look at its code:
// 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();
}
}The @Controller() decorator marks this class as a controller. The @Get() decorator on the getHello() method means this method will handle GET requests to the root path (/).
3. Service Does the Work: The controller doesn’t just provide the answer directly. It calls the getHello() method from the AppService. This is a best practice to separate routing logic from business logic.
// src/app.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}The @Injectable() decorator marks this class so it can be injected into other components (like our controller). This is where "Hello World!" is actually generated.
Step 5: Creating Our Own Custom Endpoint
Now, let’s create something more interesting. We’ll build a new endpoint GET /greeting/:name that will provide a personalized greeting.
1. Modify the Service (app.service.ts)
Add a new method to create the greeting message.
// src/app.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
// Add this new method
getGreeting(name: string): string {
return `Hello, ${name}! Welcome to your first API.`;
}
}2. Modify the Controller (app.controller.ts)
Add a new method in the controller to create the route and call the new service method we just made.
// src/app.controller.ts
import { Controller, Get, Param } from '@nestjs/common'; // Don't forget to import Param
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
// Add this new method
@Get('greeting/:name')
sendGreeting(@Param('name') name: string): string {
return this.appService.getGreeting(name);
}
}Notice:
- @Get('greeting/:name'): We define a new route. The :name part is a route parameter.
- @Param('name') name: string: We use the @Param() decorator to extract the value of the name route parameter and assign it to the name variable, typed as a string.
3. Test It!
Save all your changes. The development server will automatically restart. Now, open your browser or Postman and access our new URL, for example:
http://localhost:3000/greeting/Budi
You will get the following response:
Hello, Budi! Welcome to your first API.Try replacing “Budi” with your own name and see the result!
Conclusion
Congratulations! You have successfully created a simple REST API project with NestJS, understood its basic components (Controller, Service, Module), and even created a custom endpoint with parameters.
This is just the tip of the iceberg of what NestJS can do. The next steps you could explore are:
- Integrating with a database using TypeORM.
- Validating input using Pipes.
- Creating new modules for different features.
- Implementing authentication with Guards.
Keep experimenting and happy coding! 👨💻👩💻


