Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions versioned_docs/version-3.x/orm/benchmark.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
sidebar_position: 18
description: ORM performance benchmark
---

# Performance Benchmark

## Overview

ZenStack maintains a fork of [prisma/orm-benchmarks](https://github.com/prisma/orm-benchmarks) and included ZenStack v3 into the test matrix. This page will be periodically updated with the latest benchmark results.

Please understand ORM performance is a complex topic because different applications may have very different database configurations, data patterns and query profiles. The benchmark results should be used to understand if things are **in the right ballpark**, rather than exact performance numbers you will get in your application.

### Repository

[zenstackhq/orm-benchmarks](https://github.com/zenstackhq/orm-benchmarks)

### Configuration Notes

The Prisma tests are run with the new (Rust-free) [prisma-client](https://www.prisma.io/docs/orm/prisma-schema/overview/generators) generator and with the [relationJoins](https://www.prisma.io/docs/orm/prisma-client/queries/relation-queries#relation-load-strategies-preview) preview feature. We believe this aligns better with how the majority of users will use Prisma going forward.

### How to Read the Results

The numbers shown are in milliseconds per operation; lower is better. ZenStack's numbers are used as a baseline and compared against other ORMs. The percentage numbers in parentheses show how much faster (negative) or slower (positive) the other ORMs are compared to ZenStack.

## Results

### Local PostgreSQL

> Tests are run against a PostgreSQL database in a local Docker container.

Iteration count: 100
Dataset size: 500

Comment on lines +32 to +34
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Replace hard line-break spaces to satisfy markdownlint (MD009).

Use list items (or
) instead of trailing double spaces.

-Iteration count: 100  
-Dataset size: 500
+- Iteration count: 100
+- Dataset size: 500
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Iteration count: 100
Dataset size: 500
- Iteration count: 100
- Dataset size: 500
🤖 Prompt for AI Agents
In versioned_docs/version-3.x/orm/benchmark.md around lines 32 to 34, the two
trailing spaces at the ends of the "Iteration count: 100  " and "Dataset size:
500" lines trigger markdownlint MD009; remove the hard line-break spaces and
rewrite the two lines as proper Markdown (e.g., convert to a bulleted list, or
join into a single paragraph, or add an explicit <br/> tag) so that line breaks
are represented without trailing double spaces.

|ORM|findMany|findMany-filter-paginate-order|findMany-1-level-nesting|findFirst|findFirst-1-level-nesting|findUnique|findUnique-1-level-nesting|create|nested-create|update|nested-update|upsert|nested-upsert|delete|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|zenstack|3.62|1.23|118.28|1.08|1.10|0.64|0.95|2.10|4.48|1.70|2.64|1.42|2.53|2.02|
|prisma|3.04 (-15.95%)|1.35 (+9.86%)|134.43 (+13.66%)|1.37 (+26.98%)|1.53 (+39.37%)|0.97 (+52.42%)|1.53 (+61.20%)|1.84 (-12.67%)|4.98 (+11.30%)|1.22 (-27.88%)|3.10 (+17.41%)|2.70 (+90.26%)|2.74 (+8.18%)|1.53 (-24.27%)|
|drizzle|8.42 (+132.62%)|0.97 (-21.18%)|94.88 (-19.78%)|1.09 (+1.39%)|1.15 (+4.82%)|0.74 (+15.88%)|1.15 (+21.70%)|1.61 (-23.57%)|3.72 (-16.84%)|0.88 (-47.98%)|2.25 (-14.80%)|0.77 (-45.54%)|2.08 (-17.96%)|1.28 (-36.74%)|
|typeorm|1.73 (-52.10%)|0.73 (-40.98%)|23.24 (-80.35%)|0.87 (-19.29%)|1.30 (+18.26%)|0.37 (-42.66%)|1.06 (+11.64%)|1.80 (-14.13%)|2.80 (-37.41%)|0.51 (-69.89%)|1.41 (-46.69%)|1.60 (+12.60%)|2.02 (-20.07%)|0.91 (-54.96%)|

### Remote PostgreSQL

> Tests are run from a local machine against a PostgreSQL database from [Neon](https://neon.com/) in the us-east-1 region.

Iteration count: 20
Dataset size: 500
Comment on lines +46 to +47
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Same hard line-break issue here.

Switch to list form for consistency and linting.

-Iteration count: 20  
-Dataset size: 500
+- Iteration count: 20
+- Dataset size: 500
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Iteration count: 20
Dataset size: 500
- Iteration count: 20
- Dataset size: 500
🤖 Prompt for AI Agents
versioned_docs/version-3.x/orm/benchmark.md around lines 46 to 47: the document
currently uses two hard line-breaks ("Iteration count: 20  " and "Dataset size:
500") which breaks consistency and fails linting; replace these two hard
line-break lines with a proper markdown list (e.g., a bulleted or numbered list)
containing "Iteration count: 20" and "Dataset size: 500" so the content is
consistent with surrounding docs and passes lint checks.


|ORM|findMany|findMany-filter-paginate-order|findMany-1-level-nesting|findFirst|findFirst-1-level-nesting|findUnique|findUnique-1-level-nesting|create|nested-create|update|nested-update|upsert|nested-upsert|delete|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|zenstack|266.88|89.09|379.77|83.93|89.51|87.56|89.48|261.96|719.56|257.24|438.89|264.01|430.05|256.50|
|prisma|349.80 (+31.07%)|173.51 (+94.76%)|485.73 (+27.90%)|171.33 (+104.15%)|179.38 (+100.41%)|173.32 (+97.95%)|180.36 (+101.57%)|175.17 (-33.13%)|1043.86 (+45.07%)|174.61 (-32.12%)|681.50 (+55.28%)|613.88 (+132.52%)|603.02 (+40.22%)|178.72 (-30.32%)|
|drizzle|1067.94 (+300.16%)|177.13 (+98.83%)|284.89 (-24.98%)|174.92 (+108.42%)|178.58 (+99.51%)|176.94 (+102.08%)|180.89 (+102.16%)|183.68 (-29.88%)|716.85 (-0.38%)|179.00 (-30.42%)|532.09 (+21.24%)|176.24 (-33.25%)|540.86 (+25.77%)|180.24 (-29.73%)|
|typeorm|268.19 (+0.49%)|87.74 (-1.51%)|473.78 (+24.76%)|86.04 (+2.52%)|182.50 (+103.90%)|88.06 (+0.57%)|175.96 (+96.66%)|265.91 (+1.51%)|436.68 (-39.31%)|88.39 (-65.64%)|348.48 (-20.60%)|355.76 (+34.75%)|443.17 (+3.05%)|88.53 (-65.48%)|

## Observations

### Cold Start Overhead

While not readily observable in the numbers, ZenStack has a higher cold start overhead due to the usage of [Zod](https://zod.dev/) for input validation. Zod does JIT compilation of schemas on the first run. This overhead is amortized over multiple operations. The worst-case cold start overhead observed is around 20ms in the test environment.

### Why Is ZenStack Slower for Simple Mutations?

Right now, ZenStack wraps every mutation in an explicit transaction. Although it doesn't make a real difference on the database side because PostgreSQL will do it anyway behind the scenes, it adds communication overhead between the client and the database server.

There'll be optimizations for this in the future.
Comment on lines +1 to +66
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Quick lint sweep script (optional).

Run to catch bare URLs, trailing spaces, and repeated headings before merge.


🏁 Script executed:

#!/bin/bash
# Trailing spaces (hard breaks)
rg -nP '  $' versioned_docs/version-3.x/orm/benchmark.md
# Bare URLs (MD034)
rg -nP 'https?://\S+' versioned_docs/version-3.x/orm/benchmark.md | rg -v '\]\('
# Heading style sanity
rg -nP '^\s*#' versioned_docs/version-3.x/orm/benchmark.md

Length of output: 333


Remove trailing spaces on lines 32 and 46. Each instance introduces unintended hard breaks in the rendered Markdown.

🧰 Tools
🪛 LanguageTool

[style] ~63-~63: For conciseness, consider replacing this expression with an adverb.
Context: ... ZenStack Slower for Simple Mutations? Right now, ZenStack wraps every mutation in an ex...

(AT_THE_MOMENT)

🤖 Prompt for AI Agents
versioned_docs/version-3.x/orm/benchmark.md around lines 32 and 46: those lines
contain trailing spaces that force unintended hard line breaks in the rendered
Markdown; remove the trailing whitespace at the end of line 32 and line 46 (and
optionally run a trim-whitespace or pre-commit hook across the file to ensure no
other trailing spaces remain).