TyoeORM vs Prisma to build GraphQL APIs with TypeScript

If you are building GraphQL APIs with TypeScript and have a relational database, there are two main ORM libraries we can use: Prisma and TypeORM. Both of them are similar. They both use models to define database tables, have query APIs, handle db connection well, have good documentations and community support so on. However, if you want to know which one to use, I recommend typeorm for the reasons below.

Here are the example projects.

(1) Better integration with type-graphql

This is probably the biggest point I want to make. If you want to pick and choose which database fields to expose, you need to write two different models (the one defines table and another one to define graphql schema) with Prisma. This is because Prisma uses its own prisma.schema file to define the model.

Tables are defined in the prisma.schema file.

model book {
  id       Int    @id @default(autoincrement())
  title    String
  field    String
  authorId Int
  author   author @relation(fields: [authorId], references: [id])
}

If we are going to expose the same field as database we can just use typegraphql-prisma to generate the schema from the model in prisma.schema file. However, if we want to customise which fields to expose or expose a calculated field, we need to create a separate model with type-graphql decorators.

@ObjectType()
export class Book {
  @Field()
  id: number

  @Field()
  title: string

  @Field()
  authorId: number

  @Field(type => Author)
  author: Author
}

On the other hand, TypeORM uses regular classes and decorators for a database model. This means a class file can contain decorators for TypeORM as well as for type-graphql.


@ObjectType()
@Entity()
export class Book {

  @Field(type => Int)
  @PrimaryGeneratedColumn()
  id: number

  @Field()
  @Column()
  title: string

  @Column()
  fieldNotExposingToTheGraph: string 
  
  @Field(type => [Author])
  @ManyToMany(() => Author, author => author.books, {
    onDelete: 'CASCADE'
  })
  @JoinTable()
  authors: Author[]
}

(2) Easier to handle many to many relationship

I think it is easier to handle many to many relationships with TypeORM. We can just add @ManyToMany decorator. See my TypeORM project example where I handle many to many relationship. It’s not easy with Prisma as far as I understand. Actually, TypeORM is more intuitive when it comes to defining relationships in my opinion.

(3) More flexible

TypeORM is more flexible and provides more options. It supports both Active Record and DataMapper patterns (see doc here). It has its own query APIs like find() as well as query builder support. Writing code for database queries is more flexible with TypeORM. It’s similar to Hibernate, Doctrin and Entity Framework. If you have worked with one of those, the transition is easier.

In conclusion, if you are not really sure which one to use for your GraphQL API project, I recommend TypeORM. Having said that, both tools are very similar and Prisma is also very easy to use. If you want to investigate more, check out the projects that use Prisma and TypeORM and you can make up your own mind.

  • TypeORM project here.
  • Prisma project here.
Front-End
TypeScript: type aliases to check type equality

This post is to analyse how the type equality check by using type aliases proposed by Matt Pocock in his twitter post. These type aliases allow us to elegantly express type equality checks in unit tests. All we need to do is to pass the output and expected types in …

Front-End
Fixing it.only type error in Jest

If you are getting a type error with it.only in Jest, it could be due to incorrect TypeScript typings or incompatible versions of Jest and TypeScript. To resolve this issue, you can try the following steps: Make sure you have the latest versions of Jest and its TypeScript typings installed …

Front-End
yup conditional validation example

Here’s an example of a Yup validation logic where the first input field is optional but, if filled, it must contain only alphabetic characters, and the second input field is required: import * as Yup from “yup”; const validationSchema = Yup.object().shape({ firstField: Yup.string().matches(/^[A-Za-z]*$/, { message: “First field must contain only …