Benchmark: Prisma VS TypeORM
José Thomaz

José Thomaz @josethz00

About: Software Developer, working as full stack developer and studying about IOT, AI and compilers in the free time. Always trying to help people!

Location:
São Paulo, Brazil
Joined:
Jul 21, 2021

Benchmark: Prisma VS TypeORM

Publish Date: Aug 16 '22
56 7

Prisma and TypeORM are possibly the main ORM choices for the JavaScript ecosystem in 2022, so I have decided to do a performance benchmark comparing these two tools.

 

Notes

This is a very simple benchmark. For this I just used console.time and Excel. If there is anything wrong or uncovered, please let me know.

Prisma has recently launched a new version that makes "create" and "update" operations faster 5.1.0

 

Benchmark setup

How this benchmark was made? Which tools were used? Which database? I want to be 100% transparent in this benchmark, so I will explain every detail of how this was implemented.

Tools used

Database

I used a PostgreSQL image running inside docker containers. To have as little interference as possible between one benchmark and another, I used two databases, one for each, and in separate containers.

Test environment

Notebook Dell Inspiron 15:

  • 16GB RAM
  • Intel 7 11th gen 5.0GHz Octa-core
  • 512GB SSD
  • NVIDIA® GeForce® MX450, 2GB GDDR5
  • Kubuntu 22.04 LTS

Approach

The benchmark was divided in two different files: prisma-benchmark.ts and typeorm-benchmark.ts, and you have to measure the performance one at a time. Doing the benchmark by this way, you minimize external factors, like two simmultaneous connections to the database, garbage collector and CPU usage.

 

Benchmark code

This benchmark uses 2 different databases, but with the exact same tables: User and User_Address.

Create many Users

Code for "Create many users" in prisma-benchmark.ts:



const createManyUsers = async (count: number) => {
  const fCount = count.toLocaleString('en-US')

  const fakeUsers = Array.from({ length: count }, () => ({
    name: faker.name.fullName(),
    email: faker.internet.email(),
    password: faker.internet.password(),
    group: userGroups[Math.floor(Math.random() * userGroups.length)]
  }))

  console.time(`Create(many) ${fCount} users - PRISMA`)
  await prisma.user.createMany({
    data: fakeUsers,
  })
  console.timeEnd(`Create(many) ${fCount} users - PRISMA`)
}


Enter fullscreen mode Exit fullscreen mode

Code for "Create many users" in typeorm-benchmark.ts:



const createManyUsers = async (count: number) => {
  const fCount = count.toLocaleString('en-US')

  const fakeUsers = Array.from({ length: count }, () => ({
    name: faker.name.fullName(),
    email: faker.internet.email(),
    password: faker.internet.password(),
    group: userGroups[Math.floor(Math.random() * userGroups.length)]
  }))

  console.time(`Create(many) ${fCount} users - TYPEORM`)
  await userRepository.save(fakeUsers)
  console.timeEnd(`Create(many) ${fCount} users - TYPEORM`)
}


Enter fullscreen mode Exit fullscreen mode

Find all users

Code for "Find all users" in prisma-benchmark.ts:



const findUsers = async () => {
  console.time('Find users - PRISMA')
  await prisma.user.findMany()
  console.timeEnd('Find users - PRISMA')
}


Enter fullscreen mode Exit fullscreen mode

Code for "Find all users" in typeorm-benchmark.ts:



const findUsers = async () => {
  console.time('Find users - TYPEORM')
  await userRepository.find()
  console.timeEnd('Find users - TYPEORM')
}


Enter fullscreen mode Exit fullscreen mode

Find users that match a given condition

Code for "Find users that match a given condition" in prisma-benchmark.ts:



const findByGroup = async () => {
  console.time('Find users by group - PRISMA')
  await prisma.user.findMany({
    where: {
      group: 'guest'
    },
  })
  console.timeEnd('Find users by group - PRISMA')
}


Enter fullscreen mode Exit fullscreen mode

Code for "Find users that match a given condition" in typeorm-benchmark.ts:



const findByGroup = async () => {
  console.time('Find users by group - TYPEORM')
  await userRepository.find({
    where: {
      group: 'guest'
    },
  })
  console.timeEnd('Find users by group - TYPEORM')
}


Enter fullscreen mode Exit fullscreen mode

Creating users in a stress scenario

Code for "Creating users in a stress scenario" in prisma-benchmark.ts:



const createUsersIntensive = async (count: number) => {
  const fakeUserAddresses = Array.from({ length: count }, () => ({
    address: faker.address.streetAddress(),
    city: faker.address.city(),
    state: faker.address.state(),
    zip: faker.address.zipCode(),
    country: faker.address.country(),
  }))

  const fakeUsers = Array.from({ length: count }, () => ({
    name: faker.name.fullName(),
    email: faker.internet.email(),
    password: faker.internet.password(),
    group: userGroups[Math.floor(Math.random() * userGroups.length)],
    userAddresses: fakeUserAddresses
  }))

  console.time(`Create users intensive - PRISMA`)
  for (const user of fakeUsers) {
    await prisma.user.create({
      data: {
        ...user,
        userAddresses: {
          create: user.userAddresses
        }
      },
    })
  }
  console.timeEnd(`Create users intensive - PRISMA`)
}


Enter fullscreen mode Exit fullscreen mode

Code for "Creating users in a stress scenario" in typeorm-benchmark.ts:



const createUsersIntensive = async (count: number) => {
  const fakeUserAddresses = Array.from({ length: count }, () => ({
    address: faker.address.streetAddress(),
    city: faker.address.city(),
    state: faker.address.state(),
    zip: faker.address.zipCode(),
    country: faker.address.country(),
  }))

  const fakeUsers = Array.from({ length: count }, () => ({
    name: faker.name.fullName(),
    email: faker.internet.email(),
    password: faker.internet.password(),
    group: userGroups[Math.floor(Math.random() * userGroups.length)],
    userAddresses: fakeUserAddresses
  }))

  console.time(`Create users intensive - TYPEORM`)
  for (const user of fakeUsers) {
    await userRepository.save({
      ...user,
      userAddresses: user.userAddresses,
    })
  }
  console.timeEnd(`Create users intensive - TYPEORM`)
}


Enter fullscreen mode Exit fullscreen mode

 

Results and Conclusion

Create many plot

TypeORM and Prisma have performed almost the same in "Create Many" scenarios, with Prisma a little bit faster.

Create users in stress scenario plot

TypeORM had a far superior performance at creating new records in a stress scenario (many write requests per sec). This might be outdated, due to recent Prisma updates 5.1.0

Find all users plot

TypeORM and Prisma have performed almost the same in "Find all" scenarios, with Prisma a little bit faster.

Find users by a given condition plot

TypeORM and Prisma have performed almost the same in "Find by a given condition" scenarios.

Query scale plot

Prisma started way faster in read queries, but as new records were being written to the database, Prisma gradually lost performance and then TypeORM became faster with more or less 1800 records in the database.

Links

Comments 7 total

  • JoelBonetR 🥇
    JoelBonetR 🥇Aug 17, 2022

    Interesting topic! 😁

    I suspect in the Create Many that TypeORM uses async behind the scenes while Prisma doesn't which is the easiest explanation.

    Could you please add Sequelize to this benchmarks? It's one of the most used ORMs in Node if not the most used one for relational DBs

    Thank you! 😀

    • José Thomaz
      José ThomazAug 17, 2022

      Yes, also, Prisma has its own modelling language, so certainly some time is spent in this process of translation from .ts to .prisma. In the next benchmark I will add Sequelize and MikroORM

      • JoelBonetR 🥇
        JoelBonetR 🥇Aug 17, 2022

        Perfect thank you! Following to see the results! :)

      • Nicolas Lopes Aquino
        Nicolas Lopes AquinoAug 18, 2022

        i don't think so, as @joelbonetr said, probably TypeORM is doing some weird async thing to fetch the data. Prisma transpile all their .prisma -> .d.ts once you execute the prisma generate command. Another good strategy to see that more accurate is to create different users to the database, and then profile which queries are taking longer (you can get that by doing some queries on the pg_stat_activity

  • José María CL
    José María CLAug 19, 2022

    Great!

  • CHANG, TZU-YEN
    CHANG, TZU-YENNov 6, 2022

    I think prisma query the new data after created. (in create users intensive case)

    typeorm

    1. START TRANSACTION
    2. INSERT INTO "User"("id", "name", "email", "group", "password", "createdAt", "updatedAt") VALUES (DEFAULT, $1, $2, $3, $4, DEFAULT, DEFAULT) RETURNING "id", "createdAt", "updatedAt" -- PARAMETERS: ["Mrs. Preston Keebler","Genoveva9@gmail.com","superadmin","U7EC56fnYmfFz6o"]
    3. COMMIT
    
    Enter fullscreen mode Exit fullscreen mode

    prisma (line 3)

    1. BEGIN
    2. INSERT INTO "public"."User" ("id","name","email","group","password","createdAt","updatedAt") VALUES ($1,$2,$3,$4,$5,$6,$7) RETURNING "public"."User"."id"
    3. SELECT "public"."User"."id", "public"."User"."name", "public"."User"."email", "public"."User"."group", "public"."User"."password", "public"."User"."createdAt", "public"."User"."updatedAt" FROM "public"."User" WHERE "public"."User"."id" = $1 LIMIT $2 OFFSET $3
    4. COMMIT
    
    Enter fullscreen mode Exit fullscreen mode
    • José Thomaz
      José ThomazNov 7, 2022

      nice, thank you for the contribution

Add comment