Upload and display images using Prisma

Banner for a MediaJam post

Facundo Giuliani

Upload and display images using Prisma

Sometimes you need to handle and manage images linked to information that is stored in the database of your web application. We can improve and simplify both image management, and data storage, using two helpful products: Prisma and Cloudinary. To show how to do that, we will create a Next.js app to upload images and display them as a gallery. To handle image upload, optimization, storage, and display, we will use Cloudinary (an account will be needed). To store image details, we will use Prisma, with a local SQLite database.

What is Prisma?

Prisma is an open-source ORM (Object-Relational Mapping) for Node.js and TypeScript. It has a module to define the data models that will be used by the app, and their relationships, based on a Prisma Schema. The tool connects to a database (MySQL, PostgreSQL, SQLite) to store all the information related to the data models. There is also a Prisma Client module that offers an auto-generated query builder.

What is Cloudinary?

Cloudinary is a service for managing media assets in the cloud. You can upload images and videos, store, administer, and manipulate them. As Cloudinary is offered as a Saas (Software-as-a-Service), It has servers that handle the upload, process, and delivery of media assets, with the possibility of expansion in case the traffic of your application increases.

What is Next.js?

Next.js is a popular React framework used to create user interfaces, static pages, and server-side rendered pages, and then combine them in the same application. It allows developers to create serverless API routes using Node.js logic.

Image Gallery App

We will create an image gallery app. It will have two pages: One to upload images, and another one to list all the existing pictures. We will upload the image files to Cloudinary servers, and we will store related details in a SQLite local database using Prisma. For the user interface and the server-side logic, we will use Next.js and some NPM packages to make our work easier.

If you want to see the app live and working, here is a working CodeSandbox

Or you can go to https://prisma-upload-image.vercel.app.

If you want to see and edit the code of the app, you can clone https://github.com/fgiuliani/prisma-upload-image

Setting up

To run the app locally, you will need Node.js installed on your computer, and a Cloudinary account.

After cloning the repository, you will have to replace the values of environment variables present in .env.local file:


You can find the three values at the top left corner of your Cloudinary Dashboard page

Cloudinary Dashboard page

  • DATABASE_PROVIDER: The database provider we want Prisma to connect and use. For this example, we will use a SQLite local database. You can use a MySQL or PostgreSQL database If you want, too.

  • DATABASE_URL: The URL of the database you will use.

  • SERVER_PATH: The root path of your application. This is needed to support Next.js API routes.

You will also need to use the Terminal to run npm install in the directory where the code of the app lives, so all the involved NPM packages are downloaded and installed.

The repository already contains a SQLite database file with the schema used by Prisma to handle the data and generate the queries. In case you edit or add models in schema.prisma file you will need to run npx prisma db push --preview-feature in the Terminal, to make the database be in sync with Prisma schema.

To run the app you should go to the Terminal and run npm run dev.

Upload images using Cloudinary

Let's see how the app optimizes and uploads images using Cloudinary in utils/cloudinary.js


1 - We configure the API Key, Secret, and Cloud Name for Cloudinary integration. 2 - We call Cloudinary Uploader upload method. 3 - The first parameter of the method is the image we want to upload. cloudinary.uploader.upload method can receive the image in different ways: Using local file path, the image data (byte array buffer), the data URI, a remote address, or a private storage bucket URL. 4 - The second parameter is an options object. We will use it to define some options and modify the image before uploading it to Cloudinary servers.

Store and retrieve data using Prisma

As we defined a schema for the database, we can now use Prisma Client to build queries in a simple way. We instantiate the client in utils/prisma.js


And we use it to save information in the database, in pages/api/upload.js


We create an image with details extracted from Cloudinary upload response. We will use those details later, to conform image public URL and display it in the Gallery page.

Another cool package that we're using in the app is formidable. It helps us to handle the form submitted by the user when uploading the image, so we can generate an image buffer to be sent through the Cloudinary API. We can see how we extract an image buffer from the form data in utils/formidable.js


We can also see how we handle image upload in the page, using an <input> HTML element, in pages/upload.jsx

pages/upload.jsx pages/upload.jsx

1 - We limit the allowed file formats that our <input> element will support to only accept image files. 2 - Whenever the <input> changes its value we will update the state of imageUploaded to contain the most recent file uploaded details. 3 - When the submit button is clicked, we create a FormData object and we include the uploaded image in it. 4 - We will send that object as a parameter when we call pages/api/upload.js API route.

In pages/api/images.js we retrieve all the image records stored in the database


So we can generate an *<img>* HTML element for each image in pages/index.jsx



With this image gallery app, we see how to upload images to Cloudinary using its Node.js SDK, how to display images stored in Cloudinary servers, and how to store details related to them in a database using Prisma ORM. This example app can be used and extended for more advance and complex use cases, adding other models to the Prisma schema, or manipulating the files stored in Cloudinary with the features the platform offers.

External resources

Facundo Giuliani

Full Stack Developer

Systems Engineer from Buenos Aires, Argentina, with 15+ years of experience in software development. Full Stack Developer. Auth0 Ambassador. GitKraken Ambassador. Cloudinary Media Developer Expert. Facundo is a Senior Developer and Team Leader at MultiTracks.com, a music and tech company from Austin, Texas. He is also an open-source contributor.