apps/docs/content/docs.v6/guides/migrate-from-mongoose.mdx
This guide shows you how to migrate your application from Mongoose to Prisma ORM. We'll use a sample project to demonstrate the migration steps.
:::warning[MongoDB support for Prisma ORM v7]
MongoDB support for Prisma ORM v7 is coming in the near future. In the meantime, please use Prisma ORM v6.19 (the latest v6 release) when working with MongoDB.
This guide uses Prisma ORM v6.19 to ensure full compatibility with MongoDB.
:::
You can learn how Prisma ORM compares to Mongoose on the Prisma ORM vs Mongoose page.
:::warning
This guide currently assumes you are using Prisma ORM v6. Support for Prisma ORM v7 with MongoDB is in progress.
:::
Before starting this guide, make sure you have:
The steps for migrating from Mongoose to Prisma ORM are always the same, no matter what kind of application or API layer you're building:
These steps apply whether you're building a REST API (e.g., with Express, Koa, or NestJS), a GraphQL API (e.g., with Apollo Server, TypeGraphQL, or Nexus), or any other kind of application that uses Mongoose for database access.
First, install the required Prisma packages:
npm install [email protected] @types/node --save-dev
npm install @prisma/[email protected] dotenv
:::info[Why Prisma v6.19?]
This is the latest stable version of Prisma ORM v6 that fully supports MongoDB. MongoDB support for Prisma ORM v7 is coming soon.
You can also install prisma@6 and @prisma/client@6 to automatically get the latest v6 release.
:::
Create a new Prisma schema file:
npx prisma init --datasource-provider mongodb --output ../generated/prisma
This command creates:
prisma that contains a schema.prisma file; your Prisma schema specifies your database connection and models.env: A dotenv file at the root of your project (if it doesn't already exist), used to configure your database connection URL as an environment variableprisma.config.ts: Configuration file for PrismaThe Prisma schema uses the ESM-first prisma-client generator:
generator client {
provider = "prisma-client"
output = "../generated/prisma"
}
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}
:::tip
For an optimal development experience when working with Prisma ORM, refer to editor setup to learn about syntax highlighting, formatting, auto-completion, and many more cool features.
:::
Update the DATABASE_URL in the .env file with your MongoDB connection string:
DATABASE_URL="mongodb+srv://username:[email protected]/mydb"
:::tip
Replace username, password, cluster, and mydb with your actual MongoDB credentials and database name. You can get your connection string from MongoDB Atlas or your MongoDB deployment.
:::
The generated prisma.config.ts file should look like this:
import { defineConfig, env } from "prisma/config";
export default defineConfig({
schema: "prisma/schema.prisma",
migrations: {
path: "prisma/migrations",
},
engine: "classic",
datasource: {
url: env("DATABASE_URL"),
},
});
Add dotenv to load environment variables from your .env file:
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config";
export default defineConfig({
schema: "prisma/schema.prisma",
migrations: {
path: "prisma/migrations",
},
engine: "classic",
datasource: {
url: env("DATABASE_URL"),
},
});
:::warning
MongoDB is a schemaless database. To incrementally adopt Prisma ORM in your project, ensure your database is populated with sample data. Prisma ORM introspects a MongoDB schema by sampling data stored and inferring the schema from the data in the database.
:::
Run Prisma's introspection to create the Prisma schema from your existing database:
npx prisma db pull
This will create a schema.prisma file with your database schema.
type UsersProfile {
bio String
}
model categories {
id String @id @default(auto()) @map("_id") @db.ObjectId
v Int @map("__v")
name String
}
model posts {
id String @id @default(auto()) @map("_id") @db.ObjectId
v Int @map("__v")
author String @db.ObjectId
categories String[] @db.ObjectId
content String
published Boolean
title String
}
model users {
id String @id @default(auto()) @map("_id") @db.ObjectId
v Int @map("__v")
email String @unique(map: "email_1")
name String
profile UsersProfile?
}
MongoDB doesn't support relations between different collections. However, you can create references between documents using the ObjectId field type or from one document to many using an array of ObjectIds in the collection. The reference will store id(s) of the related document(s). You can use the populate() method that Mongoose provides to populate the reference with the data of the related document.
Update the 1-n relationship between posts <-> users as follows:
author reference in the posts model to authorId and add the @map("author") attributeauthor relation field in the posts model and it's @relation attribute specifying the fields and referencesposts relation in the users modelYour schema should now look like this:
type UsersProfile {
bio String
}
model categories {
id String @id @default(auto()) @map("_id") @db.ObjectId
v Int @map("__v")
name String
}
model posts {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String
content String
published Boolean
v Int @map("__v")
author String @db.ObjectId // [!code --]
author users @relation(fields: [authorId], references: [id]) // [!code ++]
authorId String @map("author") @db.ObjectId // [!code ++]
categories String[] @db.ObjectId
}
model users {
id String @id @default(auto()) @map("_id") @db.ObjectId
v Int @map("__v")
email String @unique(map: "email_1")
name String
profile UsersProfile?
posts posts[] // [!code ++]
}
Then, update the m-n between posts <-> categories references as follows:
categories field to categoryIds and map it using @map("categories") in the posts modelcategories relation field in the posts modelpostIds scalar list field in the categories modelposts relation in the categories model@relation attribute specifying the fields and references arguments on both sidesYour schema should now look like this:
type UsersProfile {
bio String
}
model categories {
id String @id @default(auto()) @map("_id") @db.ObjectId
v Int @map("__v")
name String
posts posts[] @relation(fields: [postIds], references: [id]) // [!code ++]
postIds String[] @db.ObjectId // [!code ++]
}
model posts {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String
content String
published Boolean
v Int @map("__v")
author users @relation(fields: [authorId], references: [id])
authorId String @map("author") @db.ObjectId
categories String[] @db.ObjectId // [!code --]
categories categories[] @relation(fields: [categoryIds], references: [id]) // [!code ++]
categoryIds String[] @map("categories") @db.ObjectId // [!code ++]
}
model users {
id String @id @default(auto()) @map("_id") @db.ObjectId
v Int @map("__v")
email String @unique(map: "email_1")
name String
profile UsersProfile?
posts posts[]
}
Generate Prisma Client based on your schema:
npx prisma generate
This creates a type-safe Prisma Client in the generated/prisma directory.
Start replacing your Mongoose queries with Prisma Client. Here's an example of how to convert some common queries:
// Find one
const user = await User.findById(id);
// Create
const user = await User.create({
email: "[email protected]",
name: "Alice",
});
// Update
await User.findByIdAndUpdate(id, {
name: "New name",
});
// Delete
await User.findByIdAndDelete(id);
// Find one
const user = await prisma.user.findUnique({
where: { id },
});
// Create
const user = await prisma.user.create({
data: {
email: "[email protected]",
name: "Alice",
},
});
// Update
await prisma.user.update({
where: { id },
data: { name: "New name" },
});
// Delete
await prisma.user.delete({
where: { id },
});
Update your Express controllers to use Prisma Client. For example, here's how to update a user controller:
import { prisma } from "../client";
export class UserController {
async create(req: Request, res: Response) {
const { email, name } = req.body;
const result = await prisma.user.create({
data: {
email,
name,
},
});
return res.json(result);
}
}
Now that you've migrated to Prisma ORM, you can:
For more information: