Skip to main content

Sever Development

A Step-by-Step Guide to Server-Side Development with NestJS

NestJS has emerged as a powerful framework for building efficient, scalable, and maintainable server-side applications. Leveraging TypeScript and inspired by Angular’s architecture, NestJS combines the best of object-oriented programming (OOP), functional programming (FP), and modular design. In this blog, we’ll walk through the core development workflow for a NestJS backend, from setup to deployment.


1. Initialize the Project

Start by setting up a new NestJS project using the CLI:

npm i -g @nestjs/cli  
nest new project-name

This generates a scaffolded project with a standard directory structure:

src/  
├── app.controller.ts
├── app.module.ts
├── app.service.ts
└── main.ts

The main.ts file bootstraps the application using NestFactory.create().


2. Modular Architecture

NestJS emphasizes modularity. Each feature (e.g., users, products) is organized into a module:

nest generate module users  
nest generate controller users
nest generate service users

This creates:

  • users.module.ts: Defines the module and its dependencies.
  • users.controller.ts: Handles HTTP requests (routes, params, validation).
  • users.service.ts: Contains business logic (e.g., interacting with a database).

Example Module:

// users.module.ts  
@Module({
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}

3. Dependency Injection (DI)

NestJS’s DI system decouples components for testability and reusability. Services are injected into controllers via constructors:

// users.controller.ts  
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}

@Get()
findAll(): User[] {
return this.usersService.findAll();
}
}

4. Middleware, Pipes, and Interceptors

  • Middleware: Process requests before they reach controllers (e.g., logging, authentication).
  • Pipes: Validate and transform incoming data (e.g., ValidationPipe with class-validator).
  • Interceptors: Modify request/response streams (e.g., error handling, logging).

Example Global Validation:

// main.ts  
app.useGlobalPipes(new ValidationPipe({ transform: true }));

5. Integrate a Database

NestJS supports various ORMs (TypeORM, Sequelize, Prisma). Here’s a TypeORM setup:

  1. Install dependencies:
npm install @nestjs/typeorm typeorm mysql2  
  1. Configure the database in app.module.ts:
@Module({  
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'password',
database: 'nest_db',
entities: [User],
synchronize: true, // Disable in production!
}),
UsersModule,
],
})
  1. Define entities and inject repositories:
// user.entity.ts  
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;

@Column()
name: string;
}

// users.service.ts
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private usersRepository: Repository<User>,
) {}

findAll(): Promise<User[]> {
return this.usersRepository.find();
}
}

6. Authentication & Authorization

Use Passport.js strategies (JWT, OAuth2) for secure authentication:

npm install @nestjs/passport @nestjs/jwt passport-jwt  

JWT Strategy Example:

// jwt.strategy.ts  
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'secret-key',
});
}

async validate(payload: any) {
return { userId: payload.sub, username: payload.username };
}
}

7. Testing

NestJS provides robust testing tools with Jest:

  • Unit Tests: Test individual services/controllers.
  • E2E Tests: Validate entire API flows.

Example Service Test:

describe('UsersService', () => {  
let service: UsersService;

beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [UsersService],
}).compile();

service = module.get<UsersService>(UsersService);
});

it('should return all users', () => {
expect(service.findAll()).toEqual([]);
});
});

8. Deployment

  1. Build the App:
npm run build  
  1. Environment Configuration:
    Use @nestjs/config to manage environment variables:
// app.module.ts  
@Module({
imports: [ConfigModule.forRoot()],
})
  1. Containerize with Docker:
FROM node:18-alpine  
WORK /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
CMD ["node", "dist/main.js"]
  1. Deploy to platforms like AWS, Heroku, or Kubernetes.

9. Monitoring & Logging

Integrate tools like:

  • NestJS’s built-in logger.
  • Prometheus for metrics.
  • Sentry for error tracking.

Conclusion

NestJS streamlines backend development by enforcing clean architecture, modularity, and modern practices. Its integration with TypeScript, DI system, and extensive ecosystem (ORM, authentication, testing) make it ideal for building enterprise-grade applications. Start small, follow the modular pattern, and gradually explore advanced features like microservices, GraphQL, and WebSockets.

Further Reading:

Happy coding! 🚀