Free Consultation

Information Technology

Build web APIs with NestJS, Postgres and Sequelize

Shreyanshi Vekariya

19 Jun 2025

5 MINUTES READ

Build web APIs with NestJS, Postgres and Sequelize

Introduction

In the connected world of today, developing scalable and dependable web APIs is crucial for any modern application. Using PostgreSQL for the database, Sequelize as the Object-Relational Mapper (ORM), and NestJS for the backend framework, this blog post will walk you through creating a robust API. You will understand how to create your development environment, connect to a PostgreSQL database, define models, and carry out CRUD (Create, Read, Update, Delete) operations by the end of this tutorial.

Why This Stack?

  • NestJS:Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript and is built with full support for TypeScript.
  • PostgreSQL: PostgreSQL is a robust, open-source object-relational database system that is renowned for its performance, feature robustness, and dependability.
  • Sequelize: Sequelize is a popular Object Relational Mapper (ORM) written in vanilla JavaScript, but there is a sequelize-typescript TypeScript wrapper that provides a set of decorators and other extras for the base Sequelize.

Requirements

  • Node.js (LTS version suggested)
  • npm or Yarn PostgreSQL
  • Basic familiarity with REST APIs and TypeScript
  • First Step: Launch Your NestJS Project
  • Let's start by making a new NestJS project. Install the NestJS CLI globally first if you haven't already:

Step 1: Set Up Your NestJS Project

Install the NestJS CLI globally first if you haven't already:

npm i -g @nestjs/cli

Create your new project:

nest new nestjs-api-boilerplate
cd nestjs-api-boilerplate

This will set up a basic NestJS application.

Step 2: Install Database Dependencies

Next, we need to install the necessary packages for PostgreSQL and Sequelize:

npm install --save @nestjs/sequelize sequelize pg pg-hstore

# pg-hstore is for serializing/deserializing JSON data

pg is the PostgreSQL driver, and sequelize-typescript enables TypeScript decorators in Sequelize models.

Step 3: Configure PostgreSQL

Make sure your PostgreSQL server is running. Create a new database for your application. For example, let's call it nestjs_api_db.

Step 4: Integrate Sequelize with NestJS

NestJS provides an @nestjs/sequelize package to easily integrate Sequelize.

  1. Create a Database Configuration Module: Let's create a database.module.ts to handle our database connection.
    // src/database/database.module.ts
      import { Module } from '@nestjs/common';
      import { SequelizeModule } from '@nestjs/sequelize';
      import { ConfigModule, ConfigService } from '@nestjs/config'; // For environment variables
    
      @Module({
        imports: [
          SequelizeModule.forRootAsync({
            imports: [ConfigModule],
            useFactory: (configService: ConfigService) => ({
              dialect: 'postgres',
              host: configService.get('DB_HOST'),
              port: configService.get('DB_PORT'),
              username: configService.get('DB_USERNAME'),
              password: configService.get('DB_PASSWORD'),
              database: configService.get('DB_DATABASE'),
              autoLoadModels: true, // Automatically load models
              synchronize: true, // Auto-create tables (for development, disable in production)
            }),
            inject: [ConfigService],
          }),
        ],
      })
      export class DatabaseModule {}
  2. Add Environment Variables: Create a .env file in your project root to store your database credentials.
    # .env
      DB_HOST=localhost
      DB_PORT=5432
      DB_USERNAME=your_pg_username
      DB_PASSWORD=your_pg_password
      DB_DATABASE=nestjs_api_db
    Important: Replace your_pg_username and your_pg_password with your actual PostgreSQL credentials.
  3. Import modules in app.module.ts : Now, import ConfigModule and DatabaseModule into your root AppModule.
    // src/app.module.ts
      import { Module } from '@nestjs/common';
      import { AppController } from './app.controller';
      import { AppService } from './app.service';
      import { ConfigModule } from '@nestjs/config';
      import { DatabaseModule } from './database/database.module';
     
      @Module({
        imports: [
         ConfigModule.forRoot({ isGlobal: true, envFilePath: '.env' }), // Load .env file globally
         DatabaseModule,
        ],
        controllers: [AppController],
        providers: [AppService],
      })
      export class AppModule {}

Step 5: Define a Sequelize Model

Let's create a simple User model.

  1. Generate a Module for Users:
    nest g module users
  2. Generate a Model and a Service:
    nest g class users/user.model --no-spec # For the Sequelize model
    nest g service users/users --no-spec    # For the service that 
    interacts with the model
  3. Define the User Model (user model.ts):
    // src/users/user.model.ts
      import { Column, Model, Table, PrimaryKey, AutoIncrement } from 'sequelize-typescript';
     
      @Table
       export class User extends Model {
        @PrimaryKey
        @AutoIncrement
        @Column
        id: number;
    
        @Column
        firstName: string;
    
        @Column
        lastName: string;
    
        @Column({ unique: true })
        email: string;
      }
  4. Register the Model in UsersModule: We need to tell Sequelize about our User model within the UsersModule.
    // src/users/users.module.ts
      import { Module } from '@nestjs/common';
      import { SequelizeModule } from '@nestjs/sequelize';
      import { User } from './user.model';
      import { UsersService } from './users.service';
      import { UsersController } from './users.controller';
      
      @Module({
        imports: [SequelizeModule.forFeature([User])], // Register the User model
        providers: [UsersService],
        controllers: [UsersController],
        exports: [UsersService], // If you want to use UsersService in other modules
      })
      export class UsersModule {}

Step 6: Implement CRUD Operations

Now, let's build the API endpoints for our User model.

Update UsersService: The service will handle the logic for interacting with the User model.

// src/users/users.service.ts
  import { Injectable } from '@nestjs/common';
  import { InjectModel } from '@nestjs/sequelize';
  import { User } from './user.model';

  @Injectable()
  export class UsersService {
    constructor(
      @InjectModel(User)
      private userModel: typeof User,
    ) {}

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

    async findOne(id: number): Promise {
      return this.userModel.findByPk(id);
    }

    async create(user: Partial): Promise {
      return this.userModel.create(user);
    }

    async update(id: number, user: Partial): Promise<[number, User[]]> {
      return this.userModel.update(user, {
        where: { id },
        returning: true, // Return the updated record
      });
    }
    async remove(id: number): Promise {
      const user = await this.findOne(id);
      await user.destroy();
    }
  }
  1. Generate a Controller for Users:
    nest g controller users/users --no-spec
  2. Update UsersController: The controller will define the API routes and call the service methods.
     // src/users/users.controller.ts
      import { Controller, Get, Post, Put, Delete, Param, Body, HttpStatus, HttpCode } from '@nestjs/common';
      import { UsersService } from './users.service';
      import { User } from './user.model';
    
      @Controller('users')
      export class UsersController {
        constructor(private readonly usersService: UsersService) {}
    
        @Get()
        async findAll(): Promise<User[]> {
          return this.usersService.findAll();
        }
    
        @Get(':id')
        async findOne(@Param('id') id: string): Promise {
          return this.usersService.findOne(+id);
        }
     
        @Post()
        @HttpCode(HttpStatus.CREATED)
        async create(@Body() createUserDto: Partial): Promise {
          return this.usersService.create(createUserDto);
        }
    
        @Put(':id')
        async update(@Param('id') id: string, @Body() updateUserDto: Partial): Promise {
          const [numberOfAffectedRows, [updatedUser]] = await this.usersService.update(+id, updateUserDto);
          return updatedUser; // Return the updated user
        }
    
        @Delete(':id')
        @HttpCode(HttpStatus.NO_CONTENT) // 204 No Content for successful deletion
        async remove(@Param('id') id: string): Promise {
          await this.usersService.remove(+id);
        }
      }
  3. Import UsersModule into AppModule:
     // src/app.module.ts 
      import { Module } from '@nestjs/common';
      import { AppController } from './app.controller';
      import { AppService } from './app.service';
      import { ConfigModule } from '@nestjs/config';
      import { DatabaseModule } from './database/database.module';
      import { UsersModule } from './users/users.module'; // Import UsersModule
    
      @Module({
        imports: [
          ConfigModule.forRoot({ isGlobal: true, envFilePath: '.env' }),
          DatabaseModule,
          UsersModule, // Add UsersModule here
        ],
        controllers: [AppController],
        providers: [AppService],
      })
      export class AppModule {}

Step 7: Run Your Application

Now, start your NestJS application:

npm run start:dev

Your API should be running on http://localhost:3000.

Step 8: Test Your API

You can use tools like Postman, Insomnia, or curl to test your API.

Examples:

Create a User (POST request):POST http://localhost:3000/users Body (JSON):

 JSON 
  {
     "firstName": "John",
     "lastName": "Doe",
     "email": "john.doe@example.com"
  }
  • Get All Users (GET request): GET http://localhost:3000/users
  • Get User by ID (GET request): GET http://localhost:3000/users/1 (replace 1 with an actual user ID)

Update a User (PUT request): PUT http://localhost:3000/users/1 Body (JSON):

  JSON
  {
     "firstName": "smith"
  }
  • Delete a User (DELETE request): DELETE
    http://localhost:3000/users/1

Next Steps

  • Validation: Implement DTOs (Data Transfer Objects) and NestJS's class-validator and class-transformer for robust input validation.
  • Authentication & Authorization: Integrate JWT, Passport.js, or other authentication strategies.
  • Error Handling: Implement global exception filters for consistent error responses.
  • Migrations: For production environments, disable synchronize: true in SequelizeModule and use Sequelize migrations for managing database schema changes.
  • Logging: Implement a proper logging strategy.
  • Pagination & Filtering: For larger datasets, implement pagination, filtering, and sorting capabilities.

Conclusion

You've used NestJS, PostgreSQL, and Sequelize to successfully create a simple web API! This stack offers a robust and well-structured approach to creating scalable backend applications. You can create complex web services by utilising the architecture of NestJS, the ORM capabilities of Sequelize, and the dependability of PostgreSQL.

Share:


Shreyanshi Vekariya
Shreyanshi Vekariya

Vue.js Developer

Shreyanshi is a skilled developer who crafts seamless, interactive user experiences with clean, efficient code. She's passionate about building responsive web apps that not only work flawlessly but look great too.

// We are here to help you

Trusting in Our Expertise

  • 30 Hours Risk Free Trial.
  • Direct Communication With Developer.
  • On-time Project Delivery Assurity.
  • Assign Dedicated PM.
  • Get Daily Update & Weekly Live Demo.
  • Dedicated team 100% focused on your product.
  • Sign NDA for Security & Confidentiality.

Collaborate with Techvoot Solutions

Upload: .jpg, .png, .pdf, .csv, .xlsx, .doc, .docx file as document.