API with NestJS #149. Introduction to the Drizzle ORM with PostgreSQL

JavaScript NestJS SQL

This entry is part 149 of 175 in the API with NestJS

Drizzle is a lightweight TypeScript ORM that lets us manage our database schema. Interestingly, it allows us to manage our data through a relational API or an SQL query builder.

In this article, we learn how to set up NestJS with Drizzle to implement create, read, update, and delete operations. We also learn how to use Drizzle to manage migrations.

Check out this repository if you want to see the full code from this article.

Connecting to the database

Let’s use Docker Compose to create a PostgreSQL database for us.

docker-compose.yml

Let’s create the file to provide Docker with the necessary environment variables.

docker.env

We must also add a matching set of variables to our NestJS application.

.env

It makes sense to check if the environment variables are available when the application starts.

app.module.ts

Setting up the connection

Drizzle can use the node-postgres library under the hood to establish a connection to the PostgreSQL database.

To handle a database connection, we can develop a dynamic module. This way, it can be easily copied and pasted into another project or maintained in a separate library.

If you’re new to dynamic modules, consider taking a look at API with NestJS #70. Defining dynamic modules

database.module-definition.ts

Since we want our to be global, we use above.

When importing the DatabaseModule, we expect specific options to be provided.

database-options.ts

Creating a connection pool

The node-postgres library suggests using a connection pool. Since we’re building a dynamic module, we can set up our pool as a provider.

database.module.ts

There’s a benefit to setting up the connection pool as a provider. It’s a great spot to add any extra asynchronous configuration if needed. We should provide the necessary configuration when importing our module.

app.module.ts

Because we defined a provider above using the string, we can now utilize it in our Drizzle service. However, before creating this service, we will need to install Drizzle.

drizzle.service.ts

Creating a schema and generating migrations

Above, we provide Drizzle with a database schema. It should describe all tables in our database. Let’s start with a simple table containing articles.

database-schema.ts

With the function, we create a new table and give it a name. We also define all of the columns using the and functions.

Managing migrations

We now need to modify our PostgreSQL database to match the above schema.

Relational databases are known for their strict data structures. We must clearly define each table’s structure, including fields, indexes, and relationships. Even with a well-designed database, our application’s evolving requirements mean the database must adapt, too. It’s critical to modify the database carefully to preserve existing data.

Manually executing SQL queries to update the structure of the database database isn’t practical across various environments. Database migrations offer a more systematic approach, allowing us to implement controlled changes like adding tables or altering columns. Modifying a database structure is a sensitive task that could potentially compromise data integrity. Database migrations involve committing SQL queries to the repository, enabling thorough reviews before they are integrated into the main branch.

To manage migrations with Drizzle, we need to install the drizzle-kit library. We will also need the dotenv library to work with environment variables.

We also need to create a config file at the root of our project.

drizzle.config.ts

Now, we can generate a migration.

When we do that, Drizzle compares the schema with our database and creates the SQL migration file.

It’s crucial to export all of the tables from the so that the Drizzle Kit can recognize them.

0000_create-articles-table.sql

The last step is to run the migration.

When we do that, Drizzle applies the changes and creates the table. This table holds information about the executed migrations.

Interacting with the database

We now have everything set up, and we can start interacting with our database through the we created.

Fetching all records

To fetch all records from a given table, we can use the method and provide the table from the schema we want.

articles.service.ts

An alternative would be to use the Query API. We will cover it in a separate article.

Fetching a record with a given ID

To fetch a single record with a given ID, we must use the function and provide a filtering condition. We throw an error if an entity with a given ID does not exist.

articles.service.ts

Creating new entities

To create new entities, we need the function. We need to call the function to ensure we can access the created entity.

articles.service.ts

Updating existing entities

To update an existing entity, we need the and functions. If the entity wasn’t updated, we throw an error.

articles.service.ts

Deleting entities

To delete an entity, we need the function. If the entity wasn’t deleted, we throw the .

articles.service.ts

Creating the controller

We can now use our service in a controller to allow users to create, read, update, and delete entities.

articles.controller.ts

Summary

Thanks to the above, we now have a fully working application that allows us to manage the database schema through Drizzle and interact with the created tables. To implement that, we had to learn how to manage migrations through the Drizzle Kit and understand the basics of accessing our data with Drizzle.

There is still more to learn when it comes to using Drizzle with NestJS, so stay tuned.

Series Navigation<< API with NestJS #148. Understanding the injection scopesAPI with NestJS #150. One-to-one relationships with the Drizzle ORM >>
Subscribe
Notify of
guest
2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
John Doe
John Doe
5 months ago

Incredible. Thank you for the tutorial, this helped me tremendously. have

ctc
ctc
4 months ago

Thanks, this helped a lot, but I have a problem if the db is downed, the nestjs only logs “AggregateError” while executing a query. How can I log the proper error for this?