DEV Community

Tochukwu Nwosa
Tochukwu Nwosa

Posted on

My First Week Learning NestJS (Coming from Frontend)

Why NestJS?

As a frontend developer, I decided to dive into backend development, and NestJS caught my attention. It's a Node.js framework inspired by Angular, designed to build scalable and maintainable server-side applications. Coming from React, the structured approach felt familiar yet different.

Let me share what I learned in my first week.


Day 1: Getting Started

What is NestJS?

NestJS is a TypeScript-first Node.js framework that uses:

  • OOP (Object-Oriented Programming)
  • FP (Functional Programming)
  • FRP (Functional Reactive Programming)

Under the hood, it uses Express by default, but you can configure Fastify too.

Setting Up

# Install NestJS CLI globally
npm i -g @nestjs/cli

# Create new project
nest new project-name

# Start development server (with hot reload)
npm run start:dev
Enter fullscreen mode Exit fullscreen mode

The development server runs on http://localhost:3000 by default.

Project Structure

When you create a new project, you get this structure:

src/
├── app.controller.ts       # Basic controller with routes
├── app.controller.spec.ts  # Unit tests
├── app.module.ts           # Root module
├── app.service.ts          # Basic service
└── main.ts                 # Entry point (bootstraps the app)
Enter fullscreen mode Exit fullscreen mode

Key insight: The main.ts file runs the bootstrap() method which calls NestFactory to create your app instance.

Creating Your First Module

# Generate a module
nest g module shops

# Generate a controller for that module
nest g controller shops
Enter fullscreen mode Exit fullscreen mode

The CLI automatically updates app.module.ts and creates the necessary files.

Basic Controller Example

import { Controller, Get } from '@nestjs/common';

@Controller('shops')
export class ShopsController {
  @Get()
  findAll(): string {
    return 'This action returns all shops';
  }
}
Enter fullscreen mode Exit fullscreen mode

Test it with Postman at http://localhost:3000/shops


Day 2: Controllers & Services

Understanding Controllers

Controllers handle incoming requests and outgoing responses. They're the messengers between your client and your business logic.

Routes are created by combining:

  • The controller prefix: @Controller('shops')
  • The HTTP method decorator: @Get('branch')
  • Result: localhost:3000/shops/branch

Response Methods in NestJS

NestJS offers two ways to send responses:

  1. Standard (recommended): Automatic status codes (200 for most, 201 for POST)
  2. Library-specific: Using Express-like syntax with @Res()

Services: Where the Logic Lives

Services are providers that handle business logic and data operations. They can be injected into multiple controllers.

# Generate a service
nest g service shops
Enter fullscreen mode Exit fullscreen mode

Or create manually:

import { Injectable } from '@nestjs/common';

@Injectable()
export class ShopsService {
  getAllShops() {
    // Business logic here
  }
}
Enter fullscreen mode Exit fullscreen mode

Injecting Services into Controllers

@Controller('shops')
export class ShopsController {
  constructor(private shopsService: ShopsService) {}

  @Get()
  getAllShops() {
    return this.shopsService.getAllShops();
  }

  @Post()
  createShop(@Body() body) {
    return this.shopsService.createShop(body.shopName);
  }
}
Enter fullscreen mode Exit fullscreen mode

The private keyword declares and initializes the service in one line—super clean!

Don't Forget the Module Configuration

@Module({
  controllers: [ShopsController],
  providers: [ShopsService], // ⚠️ IMPORTANT: Add this or you'll get errors
})
export class ShopsModule {}
Enter fullscreen mode Exit fullscreen mode

Without adding the service to providers, you'll get:

UnknownDependenciesException: Nest can't resolve dependencies...
Enter fullscreen mode Exit fullscreen mode

The Flow

HTTP Request → Controller → Service → Data Access Layer
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  • Separation of concerns: Logic stays in services, HTTP handling in controllers
  • Dependency Injection: NestJS handles this automatically by checking the providers array
  • Singletons: Services are singleton by default (one instance shared across the app)
  • Benefits: Maintainable code, easy testing with mocks, reduced coupling

The @Injectable() decorator marks a class as a provider that can be injected.


Day 3: DTOs & Validation

What are DTOs?

Data Transfer Objects (DTOs) define the structure of data sent over the network.

Why use classes over interfaces?

Classes are part of JavaScript ES6 and remain intact after compilation. NestJS can reference them at runtime, unlike TypeScript interfaces.

Creating a DTO

Create a file: create-shop.dto.ts

export class CreateShopDto {
  name: string;
  location: string;
}
Enter fullscreen mode Exit fullscreen mode

Pro tip: Create a dto folder inside your module to keep things organized.

Update DTO with PartialType

import { PartialType } from '@nestjs/mapped-types';
import { CreateShopDto } from './create-shop.dto';

export class UpdateShopDto extends PartialType(CreateShopDto) {}
Enter fullscreen mode Exit fullscreen mode

This makes all fields optional. You'll need to install:

npm install @nestjs/mapped-types -D
Enter fullscreen mode Exit fullscreen mode

Using DTOs in Controllers

@Post()
createShop(@Body() createShopDto: CreateShopDto) {
  return this.shopsService.createShop(createShopDto);
}
Enter fullscreen mode Exit fullscreen mode

Adding Validation

DTOs define structure, but don't validate yet. Enter class-validator!

npm install class-validator class-transformer
Enter fullscreen mode Exit fullscreen mode

Update your DTO:

import { IsString, IsNotEmpty } from 'class-validator';

export class CreateShopDto {
  @IsString()
  @IsNotEmpty()
  name: string;

  @IsString()
  @IsNotEmpty()
  location: string;
}
Enter fullscreen mode Exit fullscreen mode

Enable Validation Globally

In main.ts:

import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe()); // Validation enabled globally here
  await app.listen(3000);
}
bootstrap();
Enter fullscreen mode Exit fullscreen mode

Now validation runs automatically on all requests!

Handling Errors with HTTP Exceptions

When looking up a shop by ID that doesn't exist, return a proper error:

import { NotFoundException } from '@nestjs/common';

getShopById(id: string) {
  const shop = this.shops.find(shop => shop.id === id);
  if (!shop) {
    throw new NotFoundException(`Shop with ID ${id} not found`);
  }
  return shop;
}
Enter fullscreen mode Exit fullscreen mode

Key Concepts

  • DTO = Structure definition
  • Validation = Data integrity before it hits your logic
  • Pipes = Execute on arguments before route handlers

Days 4-6: Building a CRUD API

I spent these days practicing full CRUD operations, and honestly—NestJS makes it more straightforward than Express.

Having services, controllers, and modules all in one folder keeps everything organized and easier to maintain. The structure just makes sense.


My Thoughts After Week 1

What I Love:

  • Clear structure - Everything has its place
  • TypeScript integration - Type safety is a game-changer
  • CLI tools - Generating modules/controllers/services is instant
  • Dependency injection - No more messy imports everywhere
  • Familiar patterns - Coming from frontend, decorators feel natural

What Took Time:

  • Understanding the module system
  • Getting used to decorators everywhere
  • Setting up validation (but worth it!)

Next Steps:

  • Connect to a real database (MongoDB/PostgreSQL)
  • Learn about middleware and guards
  • Explore authentication with JWT
  • Database relations and TypeORM

Resources That Helped


If you're a frontend developer curious about backend, I'd say give NestJS a shot. The learning curve is gentler than raw Express, especially if you're already comfortable with TypeScript and modern frameworks.

What's your backend journey been like? Drop your experiences in the comments! 👇


Connect With Me

I'm building in public and would love to connect!

🌐 Portfolio: tochukwu-nwosa.vercel.app
🚀 Latest Project: Tech Linkup - Discover tech events and connect with innovators in Nigerian cities
💼 LinkedIn: nwosa-tochukwu
🐙 GitHub: @tochukwunwosa
🐦 Twitter/X: @tochukwudev


This is part of my #LearningInPublic series where I document my transition from frontend to full-stack development. Follow along for more!

Top comments (0)