Typeorm vs Prisma. (I created the same backend w/each)
I created the same backend with Typeorm and Prisma to decide which is the better ORM to use with Node.js and typescript. This article will go into the details of Typeorm vs Prisma and help you decide which ORM to use in your project.
Last Updated: January 2, 2022
nest.js
prisma
typeorm
If you are creating a backend with Node.js, you probably want an ORM. This can help abstract away the tedious SQL queries, into usable code. Two of the most popular ORMs for Typescript developers is Prisma and Typeorm. To help you decide which ORM to use, I created the same backend with each, then compared the two to decide the best ORM. The main criteria in deciding will be: Documentation/Popularity, CLI & Tooling, Schema, and CRUD operations.
Popularity
To judge popularity I will compare the # of issues, and stars on Github, as well as the # of weekly downloads on NPM.
Prisma
- 19.2k stars
- 1.7k issues
- 170k weekly downloads
Typeorm
- 26.7k stars
- 1.4k issues
- 468k weekly downloads
These numbers are as of January 2nd, 2022, and could change at any moment, but currently Typeorm is more popular and has more users. Also, Typeorm has less open issues on Github than Prisma does, which while is not the ultimate indicator of a projects health, it is worth noting.
Winner: Typeorm
Documentation
The documentation for Typeorm is here.. Prisma's documentation is here.. Prisma's docs are much better than Typeorm's. More examples are included with Prisma's docs, as well as search feature, and a more intuitive way of displaying information. Typeorm's docs just feel clunky at best and the lack of a search feature seems behind the times. Look at both docs yourself to decide but for me the winner is definitely Prisma.
Winner: Prisma
CLI & Tooling
Both Typeorm's and Prisma's CLI allow them to create migrations, setup projects, etc. However Prisma goes beyond this by offering more tooling such as Prisma Studio, which is a great way to inspect your database graphically, and works well with Prisma's schema file. Prisma also offers Prisma Migrate which helps with deploying migrations to databases and Prisma data platform which will host your database. However, Prisma data platform is still in early access and I haven't used it yet so only time will tell if it live up to the hype.
Winner: Prisma
Schema
This is where Typeorm and Prisma are fundamentally different. Typeorm handles the schema in classes, and uses Typescript decoraters to tell the ORM what is what. Here is an example of a Todo
entity that I created in my backend that works with Typeorm.
import {Column, CreateDateColumn, Entity, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn} from "typeorm"; import User from "../../users/entities/user.entity"; @Entity() export default class Todo { @PrimaryGeneratedColumn() id: number; @Column() title: string; @Column({nullable: true}) description: string; @ManyToOne(() => User, (user) => user.todos, {nullable: false, onDelete: "CASCADE"}) user: User; @Column() userId: number; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; }
Here you see that the class is marked with Entity()
which tells Typeorm that this should be a table. Then the classes fields are decorated with what type of column they should be such as: PrimaryGeneratedColumn()
, Column()
, CreatedDateColumn()
, etc. You can also pass in options inside of the decoraters to set nullable
cascade deletes and more. View the documentation here to see more about how Typeorm handles entities.
Prisma on the other hand uses a schema file to design the database. Here is the same Todo
table, but inside of the schema.prisma
file:
generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model User { id Int @id @default(autoincrement()) name String todos Todo[] } model Todo { id Int @id @default(autoincrement()) title String description String? user User? @relation(fields: [userId], references: [id]) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt userId Int? }
This schema file is easy to understand and reads nice. However it is not supported in Intellij and the recommended plugin doesn't work. So in order for me to code this file I had to use Visual Studio Code to code it which if you already use that is not a big deal, however if you use Intellij than it is very annoying. Otherwise the schema is nice and then when you run prisma generate
in the terminal all of the client connection code will be generated for you to start coding your backend.
Winner: preference
CRUD Operations
View the documentation here to see the full code for CRUD operations. I use Nest.js to create the app. Inside of my todo.service.ts
for my Prisma project, just import the PrismaService
which contains all of your client generated code and then your good to start coding. Here is an example of CRUD operations for Prisma:
//todo.service.ts import {Injectable} from '@nestjs/common'; import {PrismaService} from "../prisma-service/prisma.service"; import {Prisma, Todo, User} from "@prisma/client"; type todoPaginateParams = { skip?: number; take?: number; where?: Prisma.TodoWhereInput, orderBy?: Prisma.TodoOrderByWithRelationInput; } @Injectable() export class TodoService { constructor(private prisma: PrismaService) {} todo(id: number): Promise<Todo | undefined> { return this.prisma.todo.findUnique({ where: { id } }) } getUsersTodos(userId: number, params?: todoPaginateParams | undefined): Promise<Todo[]> { const {where, ...other} = params; return this.todos({ ...other, where: { userId } }) } todos(params: todoPaginateParams): Promise<Todo[]> { return this.prisma.todo.findMany(params); } createTodo(data: Prisma.TodoCreateInput): Promise<Todo> { return this.prisma.todo.create({data}) } updateTodo(id: number, data: Prisma.TodoUpdateInput): Promise<Todo> { return this.prisma.todo.update({ where: { id: id, }, data }); } deleteTodo(id: number): Promise<Todo> { return this.prisma.todo.delete({ where: { id } }); } }
The code is self explanatory and because prisma has generated the types then you get could type inference and auto-completion while coding this up.
Typeorm works good with Nest.js as well. You can use Nest.js's dependency injection to get your repo. Because Typeorm doesn't generate code it uses generics when working on the repo. The type support for this is not as good as Prisma's but it works. Here is the code to create the same Todo Service, but with Typeorm:
type todoPaginateParams = { skip?: number; take?: number; where?: string | ObjectLiteral | FindConditions<User> | FindConditions<User>[] } @Injectable() export class TodosService { constructor(@InjectRepository(Todo) private todoRepo: Repository<Todo>) { } todo(id: number): Promise<Todo> { return this.todoRepo.findOne(id); } getUsersTodos(userId: number, todoParams ?: todoPaginateParams): Promise<Todo[]> { return this.todoRepo.find({ where: { userId: userId, }, skip: todoParams.skip, take: todoParams.take }) } createTodo(data: CreateTodoDto): Promise<Todo> { const todo = this.todoRepo.create(data); return this.todoRepo.save(todo); } updateTodo(id: number, data: Partial<Todo>): Promise<Todo> { return this.todoRepo.save({ id, data }) } async deleteTodo(id: number): Promise<void> { await this.todoRepo.delete(id); } }
As you can see CRUD is very similar with each; however, I had a better experience with Prisma because of the generated code's better type inference and auto completion by my editor.
Winner: Prisma
Additional Considerations
One additional consideration for Prisma is the lack of stability. When Prisma moved to version 2, they completely changed everything leading to many breaking changes and companies having to rewrite their code. Then they said they had begin to support Go, but as of recent, they just dropped Go support. This lack of stability is a major turnoff for large companies, and if you expect the code you write to last a long time, can lead to you choosing Typeorm.
Winner: Typeorm
Conclusion
Overall, I think that having both these ORMs brings much needed competition to help bring benefits to all of use. But when choosing, Prisma has more features and a better developer experience while coding. Also, Prisma's tooling surrounds it exceeds almost any other ORM in existance. However, Typeorm brings stability and a consistant experience when coding. The choice is up to you.
Thank you for reading this article and if you enjoyed it share it on social media, or leave a comment below. As always the code is on Github (link is at the top of article).
Comments
Loading...