How to Connect to PostgreSQL in NestJS

Updated: December 31, 2023 By: Guest Contributor Post a comment

Introduction

Connecting an application to a database is a critical task for most backend systems. In this tutorial, we’ll learn how to connect a NestJS application to a PostgreSQL database using the latest syntax of NestJS and TypeScript, ensuring your application can interact with stored data effectively.

To follow along with this tutorial, you should have Node.js, NestJS CLI, and PostgreSQL installed on your system. Additionally, a basic understanding of TypeScript and NestJS concepts is recommended.

Setting up a New NestJS Project

Begin by creating a new NestJS project if you haven’t already:

$ nest new project-name

Navigate into your project directory:

$ cd project-name

Installing Required Modules

Install the @nestjs/typeorm module and pg which is the PostgreSQL client for Node.js:

$ npm install @nestjs/typeorm typeorm pg

Database Configuration

Add the TypeORM configuration to your app.module.ts:

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: 'localhost',
      port: 5432,
      username: 'your_username',
      password: 'your_password',
      database: 'your_database',
      entities: [],
      synchronize: true,
    }),
    //...other modules
  ],
  //...other decorators
})
export class AppModule {}

Replacing 'your_username', 'your_password', and 'your_database' with your PostgreSQL credentials.

Creating a Database Entity

Define a new entity that correlates with your database table. Create a new file user.entity.ts with the following content:

import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column()
  email: string;
}

Don’t forget to include them in the entities array of your TypeORM configuration.

Creating a Module

Create a module that uses the repository pattern to interact with your PostgreSQL data:

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UserService } from './user.service';

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  providers: [UserService],
  exports: [UserService],
})
export class UserModule {}

Creating a Service

Create a service user.service.ts to handle business logic:

import { Injectable } 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 userRepository: Repository<User>,
  ) {}

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

  findOne(id: string): Promise<User> {
    return this.userRepository.findOne(id);
  }

  // Other CRUD operations
}

Creating a Controller

A controller can manage incoming requests. Here is a simple example for user.controller.ts:

import { Controller, Get, Param } from '@nestjs/common';
import { UserService } from './user.service';
import { User } from './user.entity';

@Controller('users')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Get()
  findAll(): Promise<User[]> { 
    return this.userService.findAll(); 
  }

  @Get(':id')
  findOne(@Param('id') id: string): Promise<User> {
    return this.userService.findOne(id);
  }

  // Other endpoints
}

Environment Variables for Safety

It’s a best practice to use environment variables instead of hardcoding your database credentials.

import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';

// Within your AppModule or a suitable module

// Load ConfigModule which assists with environment variables
ConfigModule.forRoot({ envFilePath: '.env' });

// Refactor your TypeOrmModule setup to use environment variables
TypeOrmModule.forRoot({
  type: 'postgres',
  host: process.env.DB_HOST,
  port: parseInt(process.env.DB_PORT, 10),
  username: process.env.DB_USERNAME,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  // ...other properties
  // entities and synchronize as previously stated
})

Advanced Usage

Advanced configurations can involve separate environments, migrations, listeners/subscribers, and much more. You might need to configure additional options as your application grows.

Conclusion

In this tutorial, we’ve established a connection from a NestJS application to a PostgreSQL database, we’ve created entities, modules, services, and controllers to structure access to and querying of the database. Make sure to secure your application by using environment variables for your database credentials and keep growing your application with advanced TypeORM and NestJS features.