API with NestJS #178. Storing files inside of a PostgreSQL database with Drizzle

Uncategorized

This entry is part 178 of 178 in the API with NestJS

When working with PostgreSQL, we can use the bytea column to store binary data, such as images, PDFs, or other small files. In this article, we explore how to store files in a PostgreSQL database using the Drizzle ORM. We also learn how to stream the data to our users.

Using the bytea column with the Drizzle ORM

Unfortunately, the Drizzle ORM does not support the bytea column natively. Thankfully, we can define a custom type to handle it.

bytea.ts

By specifying , we state that when the Drizzle ORM fetches the data from the database, it will be a . Also, TypeScript will ensure that we use a  when we insert the data into the database.

If you want to know more about the , check out Node.js TypeScript #3. Explaining the Buffer

Now, we can add a table to our database that uses the custom column we created.

database-schema.ts

We will use the column to store the type of the file.

Let’s generate a migration that creates our table.

0000_add-files-table.sql

Storing the files

We first need to create a service to store the files in our database.

files.service.ts

Our service requires the user to provide the name of the file, its type, and the buffer containing the binary data. To receive that from the user, we need to use the , which utilizes the multer library under the hood.

files.controller.ts

To access the type, we need to install the package.

To send us a file, the user needs to make a request containing the multipart/form-data.

If you want to know more about multipart/form-data, check out Node.js TypeScript #6. Sending HTTP requests, understanding multipart/form-data

Streaming the files

Let’s create a way for our users to receive the stored files. The first step is to add a new method to our service.

files.service.ts

Now, we need to create an endpoint that streams the file to the user. The most straightforward approach is to use the object through the decorator.

files.controller.ts

If you want to know more about writeable streams, check out Node.js TypeScript #5. Writable streams, pipes, and the process streams

To help the browser recognize the file type and treat it accordingly, we should attach additional headers, such as and .

files.controller.ts

Thanks to attaching the filename in the header, the browser will suggest the correct filename if the user tries to store the file on their drive.

However, when we use the decorator in the above way, we give up some of the features provided by NestJS. Fortunately, we can deal with that by using the option together with the constructor.

files.controller.ts

Summary

In this article, we’ve explored a simple way of uploading files to PostgreSQL and streaming them to our users using PostgreSQL, NestJS, and the Drizzle ORM.

Using the bytea column in PostgreSQL makes it very simple to store binary data. This approach avoids relying on external services such as S3 from AWS. It also allows us to take advantage of database features such as transactions and backups. Unfortunately, using the bytea column to store large files can reduce our performance. Therefore, we should avoid using the bytea column for large files or when performance and scalability are critical.

Series Navigation<< API with NestJS #177. Response serialization with the Drizzle ORM
Subscribe
Notify of
guest
1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Marc
Marc
5 days ago

This is great. Thank you. Would you have an example using the “large object” extension for postgres?