In this guide, we will create a Prisma MongoDB application using Typescript. The main objective is to build a small Prisma MongoDB example from scratch that can be extended further for bigger requirements.

While Prisma works extremely well with relational databases such as MySQL and Postgres, there is still confusion about using it with MongoDB. We will be clearing that in this post.

1 – Prisma MongoDB Pre-Requisites

Can you use Prisma with MongoDB?

This is probably the first question that pops up about Prisma MongoDB. The answer is Yes.

We can use Prisma with MongoDB. However, the MongoDB connector is currently a preview feature. This means that we need some additional configuration to make it work.

The other pre-requisites for using MongoDB with Prisma are as follows:

  • We should have Node.js on our machine.
  • MongoDB server should have a replica set deployment.

The MongoDB database connector uses transactions to support nested writes. We get errors if we try to actually write to a database that does not have replication.

(node:1165) UnhandledPromiseRejectionWarning: Error: 
Invalid `prisma.book.create()` invocation in
/Users/saurabhdashora/PrismaProjects/prisma-mongodb/index.ts:8:23

   5 async function main() {
   6     await prisma.$connect()
   7 
→  8     await prisma.book.create(
  Error occurred during query execution:
ConnectorError(ConnectorError { user_facing_error: None, kind: RawDatabaseError { code: "unknown", message: "Command failed (IllegalOperation): This MongoDB deployment does not support retryable writes. Please add retryWrites=false to your connection string.)" } })
    at cb (/Users/saurabhdashora/PrismaProjects/prisma-mongodb/node_modules/@prisma/client/runtime/index.js:38707:17)
    at async PrismaClient._request (/Users/saurabhdashora/PrismaProjects/prisma-mongodb/node_modules/@prisma/client/runtime/index.js:40853:18)

However, supporting transactions means that we need to have a replica set. There are a couple of ways to solve this.

First option is to use MongoDB Atlas. It is a free-service where we can create MongoDB cluster that supports replication.

The second option is to setup a local MongoDB server with replication.

I prefer the second option as it is pretty straightforward (no account registration process) and also gives you more control in a development environment where it might not be feasible to connect to an external service.

2 – Installation of Prisma Packages

Next step is to setup the project and install the necessary packages.

To do so, execute the below commands:

$ mkdir prisma-mongodb
$ npm init -y
$ npm install prisma --save-dev

Prisma is a development dependency. Therefore, we use the flag –save-dev.

Now, we need to invoke the Prisma CLI.

$ npx prisma

Next, we can setup our Prisma project.

$ npx prisma init

Basically, this command creates a new directory in our project with the name prisma. This directory will contain a file schema.prisma. Also, there will be .env file in the root of the project.

We can now proceed with the Typescript setup.

3 – Typescript Setup

We also need to setup Typescript for our project.

First step is to install the necessary packages:

$ npm install typescript ts-node @types/node --save-dev

All of these are also dev dependencies.

We also need to create the tsconfig.json file.

{
    "compilerOptions": {
      "sourceMap": true,
      "outDir": "dist",
      "strict": true,
      "lib": ["esnext"],
      "esModuleInterop": true
    }
}

Basically, this configuration file specifies Typescript compiler options.

4 – Prisma MongoDB Connection Setup

In Prisma, we connect the database by setting the url property of the datasource block within the schema.prisma file.

See below:

datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}

The url is set using an environment variable in the .env file. Since, we are using local MongoDB, we can provide the URL as below:

DATABASE_URL="mongodb://localhost:27017/mydb"

Here, myDB is the database. In case, you are using MongoDB Atlas, you can provide the connection string provided by them.

Also, as discussed earlier, MongoDB is a preview feature for Prisma at the time of writing. Therefore, we need to configure the previewFeatures property in the generator block in the schema.prisma.

generator client {
  provider = "prisma-client-js"
  previewFeatures = ["mongoDb"]
}

In future, this piece of configuration may change or be removed altogether.

5 – Create Prisma Schema

Now that the configurations are in place, we need to define the schema. Basically, the schema is nothing but our DB model.

For our example, we will create a simple Book model. Just like other configuration items, the schema is also defined in the prisma.schema file.

model Book {
  id      String @id @default(dbgenerated()) @map("_id") @db.ObjectId
  title   String
  author  String
}

As you can see, we have three fields. The id is automatically generated. As per MongoDB convention, we map it to _id field. The other fields are title and author.

We can also define other models and their relations in the same file.

6 – Install Prisma Client

Prisma Client generates the necessary client libraries for us to interact with our database.

We can install Prisma Client using the below command.

$ npm install @prisma/client

Basically, the install command invokes prisma generate. It runs over our Prisma schema and generates a client based on our models. In other words, the client is tailored to our model.

Whenever we make changes to our Prisma schema, we need to generate a new version of the client. However, we don’t need to install Prisma client again. We can simply invoke prisma generate to apply the new changes.

7 – Read & Write Data using Prisma Client

Once we have the Prisma Client, we can start writing queries for our database.

For our demo application, we can write a couple of functions. However, for a real production application, we might build a REST API. In case you are interested, you can go through this post about creating a NestJS Prisma REST API from scratch.

To demonstrate MongoDB Prisma integration, we will write some Typescript code.

See below:

import { PrismaClient } from ".prisma/client";

const prisma = new PrismaClient()

async function main() {
    await prisma.$connect()

    await prisma.book.create({
        data: {
            title: 'Way of Kings',
            author: 'Brandon Sanderson'
        }
    })

    const books = await prisma.book.findMany()

    console.log(books)
}

main()
    .catch((error) => {
        throw error
    })
    .finally(async () => {
        await prisma.$disconnect()
    })

Here, we basically import the Prisma Client and create a new instance of the client. Then, we use $connect() to connect our script to the database.

Once the connection is established, we can write to the database using create() function and also query the same records using findMany() function. These functions are available as part of the Prisma Client we had generated in the previous step.

Finally, we also close the database connections when the script terminates.

We can now run the script using the below command:

$ npx ts-node index.ts

We will see the Book record displayed in the console.

[
  {
    id: '6200cca6025fd66acd58b4f4',
    title: 'Way of Kings',
    author: 'Brandon Sanderson'
  },
]

Conclusion

With this, we have successfully created a Prisma MongoDB application using Typescript. We started by exploring the various options for MongoDB setup using replica set. Proceeding further, we looked at the Prisma and Typescript setup to create the Prisma Client. Finally, we wrote some queries to see Prisma MongoDB in action.

The code for this post is available on Github for reference.

If you have any comments or queries about this post, please feel free to mention them in the comments section below.


Saurabh Dashora

Saurabh is a Software Architect with over 12 years of experience. He has worked on large-scale distributed systems across various domains and organizations. He is also a passionate Technical Writer and loves sharing knowledge in the community.

0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *