In this full tutorial, learn how to build a RESTful CRUD API using NestJS, TypeORM, and PostgreSQL. Follow step-by-step instructions to set up a scalable backend, create database models, and implement endpoints for creating, reading, updating, and deleting data. Perfect for modern web and mobile app development.
Setting Up NestJS, TypeORM, and PostgreSQL
To get started building a CRUD API with NestJS, TypeORM, and PostgreSQL, you’ll first need to set up your development environment. This includes installing the NestJS CLI, creating a new project, and configuring the database connection.
1. Prerequisites
Before we begin, make sure you have the following installed:
- Node.js (v18 or above)
- npm or Yarn
- PostgreSQL (make sure the service is running)
- NestJS CLI (install globally using the command below)
npm install -g @nestjs/cli
2. Create a New NestJS Project
Generate a new NestJS project using the CLI:
nest new nest-crud-api
Choose your preferred package manager (npm or yarn) when prompted.
3. Install Required Dependencies
Next, navigate into your project directory and install TypeORM and PostgreSQL driver:
cd nest-crud-api
npm install --save @nestjs/typeorm typeorm pg
4. Set Up TypeORM Configuration
Open src/app.module.ts and configure the TypeORM module with your PostgreSQL database credentials:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'your_postgres_username',
password: 'your_postgres_password',
database: 'nest_crud_db',
autoLoadEntities: true,
synchronize: true, // Disable in production
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
🔐 Note: The synchronize: true option automatically syncs your entity schemas with the database — convenient for development but not recommended for production.
5. Create the PostgreSQL Database
Ensure you’ve created the database nest_crud_db in your PostgreSQL instance. You can use psql or any database GUI like pgAdmin:
psql postgres -U djamware
CREATE DATABASE nest_crud_db;
\q
Creating the User Module and Entity
In this section, we'll generate the User module, controller, and service, and define the corresponding database entity using TypeORM.
1. Generate User Module, Controller, and Service
Use the NestJS CLI to quickly scaffold the required files:
nest generate module user
nest generate controller user
nest generate service user
This creates the following structure:
src/
├── user/
│ ├── user.module.ts
│ ├── user.controller.ts
│ ├── user.service.ts
2. Create the User Entity
Create a new file named user.entity.ts inside the user folder:
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column({ unique: true })
email: string;
@Column()
password: string;
}
3. Register the Entity in UserModule
Update the user.module.ts file to include the TypeOrmModule and register the User entity:
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UserService } from './user.service';
import { UserController } from './user.controller';
@Module({
imports: [TypeOrmModule.forFeature([User])],
providers: [UserService],
controllers: [UserController],
})
export class UserModule { }
4. Import UserModule in AppModule
Finally, update app.module.ts to import the UserModule:
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserModule } from './user/user.module';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'your_postgres_username',
password: 'your_postgres_password',
database: 'nest_crud_db',
autoLoadEntities: true,
synchronize: true,
}),
UserModule,
],
})
export class AppModule {}
Implementing CRUD Operations for the User API
1. Implement UserService Methods
Open src/user/user.service.ts and add methods for Create, Read, Update, and Delete:
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
@Injectable()
export class UserService {
constructor(
@InjectRepository(User)
private readonly userRepository: Repository<User>,
) { }
async create(userData: Partial<User>): Promise<User> {
const user = this.userRepository.create(userData);
return this.userRepository.save(user);
}
async findAll(): Promise<User[]> {
return this.userRepository.find();
}
async findOne(id: number): Promise<User> {
const user = await this.userRepository.findOneBy({ id });
if (!user) {
throw new NotFoundException(`User with ID ${id} not found`);
}
return user;
}
async update(id: number, userData: Partial<User>): Promise<User> {
await this.userRepository.update(id, userData);
return this.findOne(id);
}
async remove(id: number): Promise<void> {
const result = await this.userRepository.delete(id);
if (result.affected === 0) {
throw new NotFoundException(`User with ID ${id} not found`);
}
}
}
2. Implement UserController Routes
Open src/user/user.controller.ts and define the REST endpoints:
import { Controller, Get, Post, Body, Param, Put, Delete } from '@nestjs/common';
import { UserService } from './user.service';
import { User } from './user.entity';
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) { }
@Post()
create(@Body() userData: Partial<User>): Promise<User> {
return this.userService.create(userData);
}
@Get()
findAll(): Promise<User[]> {
return this.userService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string): Promise<User> {
return this.userService.findOne(+id);
}
@Put(':id')
update(@Param('id') id: string, @Body() userData: Partial<User>): Promise<User> {
return this.userService.update(+id, userData);
}
@Delete(':id')
remove(@Param('id') id: string): Promise<void> {
return this.userService.remove(+id);
}
}
3. Test the API
You can now test the API using tools like Postman or Insomnia.
npm run start
The available endpoints are:
- POST /users – Create a user
- GET /users – Get all users
- GET /users/:id – Get a single user by ID
- PUT /users/:id – Update a user by ID
- DELETE /users/:id – Delete a user by ID
Adding Input Validation with DTOs and class-validator
1. Install Validation Packages
NestJS uses class-validator and class-transformer for validation. If they’re not installed yet, add them:
npm install class-validator class-transformer
2. Create DTOs for User
Create a new file user.dto.ts inside the user folder and define two DTOs — one for creating a user and another for updating:
// src/user/user.dto.ts
import { IsEmail, IsNotEmpty, IsOptional, MinLength } from 'class-validator';
export class CreateUserDto {
@IsNotEmpty()
name: string;
@IsEmail()
email: string;
@MinLength(6)
password: string;
}
export class UpdateUserDto {
@IsOptional()
@IsNotEmpty()
name?: string;
@IsOptional()
@IsEmail()
email?: string;
@IsOptional()
@MinLength(6)
password?: string;
}
3. Enable ValidationPipe Globally
Open main.ts and enable global validation:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe());
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
4. Update Controller to Use DTOs
Update user.controller.ts to use the DTOs:
import { Body, Controller, Delete, Get, Param, Post, Put } from '@nestjs/common';
import { UserService } from './user.service';
import { User } from './user.entity';
import { CreateUserDto, UpdateUserDto } from './user.dto';
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) { }
@Post()
create(@Body() createUserDto: CreateUserDto): Promise<User> {
return this.userService.create(createUserDto);
}
@Get()
findAll(): Promise<User[]> {
return this.userService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string): Promise<User> {
return this.userService.findOne(+id);
}
@Put(':id')
update(
@Param('id') id: string,
@Body() updateUserDto: UpdateUserDto,
): Promise<User> {
return this.userService.update(+id, updateUserDto);
}
@Delete(':id')
remove(@Param('id') id: string): Promise<void> {
return this.userService.remove(+id);
}
}
Now your API will:
- Reject invalid emails or short passwords
- Accept only defined and validated fields
- Transform and sanitize input using DTOs
Conclusion
In this tutorial, you learned how to build a complete CRUD REST API using NestJS, TypeORM, and PostgreSQL. We covered setting up the project, creating a User module with entity and database integration, implementing CRUD operations, and adding input validation with DTOs and class-validator.
This foundation can be extended with features like authentication (JWT), pagination, filtering, or relational entities for real-world applications. NestJS’s modular structure and powerful tooling make it an excellent choice for building scalable and maintainable backend APIs.
You can find the full source code on our GitHub.
That just the basic. If you need more deep learning about Node, Express, Sequelize, PostgreSQL/MySQ or related you can take the following cheap course:
- Sequelize ORM with NodeJS
- Angular + NodeJS + PostgreSQL + Sequelize
- PostgreSQL 2019 MasterClass
- ORDBMS With PostgreSQL Essential Administration Training
- Node. js: Node. js App Development - Novice to Pro!: 4-in-1
Thanks!