docs(blog): add article on reducing Prisma database operations by 60% - #8132
docs(blog): add article on reducing Prisma database operations by 60%#8132akb898 wants to merge 1 commit into
Conversation
Linear: TBD by DevRel
|
@akb898 is attempting to deploy a commit to the Prisma Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughChangesPrisma optimization article
Author metadata
Estimated code review effort: 3 (Moderate) | ~20 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx`:
- Around line 1-15: Add the required Linear issue reference to the blog post
frontmatter or content, using the created issue’s ID or URL. Update the article
identified by its title and slug, and ensure the reference is present before
merge.
- Around line 9-10: Add the missing hero.png and meta.png assets at the paths
referenced by heroImagePath and metaImagePath in the blog front matter before
publication, or defer publication until both files are available.
- Around line 173-189: Revise the “Use findUnique for exact lookups” section and
its comparison comments to avoid claiming that findFirst necessarily performs a
scan or that findUnique is inherently faster. State that findUnique is the
semantically appropriate API for unique predicates, acknowledge PostgreSQL may
use an index lookup for findFirst({ where: { id } }), and recommend EXPLAIN
ANALYZE for validating performance conclusions.
- Around line 432-439: Update the partial-index guidance in the soft-delete
section to show enabling Prisma’s partialIndexes generator preview feature and
defining the index with a Prisma @@index declaration using its where predicate.
Remove the statement that this requires a raw migration, while retaining the SQL
example only if it remains useful context.
- Around line 197-220: Update the User model’s totalRevenue field from Float to
Decimal with an appropriate `@db.Decimal` precision and scale, and ensure the
order amount passed to the transactional increment uses a Decimal value.
Preserve the existing totalOrders and atomic prisma.$transaction update
behavior.
- Around line 128-137: Update the Prisma order-loading example around
prisma.order.findMany and its explanation so it does not claim include always
produces one SQL query. Either configure the valid relationLoadStrategy
single-query option when guaranteeing one query, or describe include as avoiding
N+1 with a fixed number of queries without asserting a single round trip.
- Line 226: The conclusion around the counter-verification statement and the FAQ
answer near the corresponding FAQ section must remove rollback as a drift cause.
Explain that rollbacks revert both the order creation and counter update, and
identify valid causes instead: writes bypassing counter maintenance, manual
updates, migrations or incomplete migrations, and incorrect reconciliation
logic.
- Around line 263-271: Update the Prisma Client setup preceding the
cacheStrategy example to show the Accelerate-backed configuration, including the
required accelerateUrl and extension setup. Ensure the categories.findMany
example can compile with cacheStrategy enabled, while preserving the existing
query behavior.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: c450a90a-77ed-409f-a019-68328559e7de
⛔ Files ignored due to path filters (1)
apps/blog/public/authors/aman-bind.pngis excluded by!**/*.png
📒 Files selected for processing (2)
apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdxapps/blog/src/lib/author-bios.ts
| --- | ||
| title: "How I Cut Prisma Database Operations by 60% Without Upgrading My Database" | ||
| slug: "cut-prisma-database-operations-60-percent" | ||
| date: "2026-08-05" | ||
| authors: | ||
| - "Aman Kumar Bind" | ||
| metaTitle: "How I Cut Prisma Database Operations by 60% Without Upgrading My Database" | ||
| metaDescription: "Profile, index, and fix the Prisma ORM patterns that silently multiply database operations: N+1 queries, over-fetching, write loops, soft-delete bloat, and JSONB anti-patterns." | ||
| heroImagePath: "/cut-prisma-database-operations-60-percent/imgs/hero.png" | ||
| metaImagePath: "/cut-prisma-database-operations-60-percent/imgs/meta.png" | ||
| heroImageAlt: "A dashboard graph showing database operations dropping by 60% over one weekend of optimization" | ||
| tags: | ||
| - "education" | ||
| - "orm" | ||
| --- |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Add the required Linear reference.
The PR objective requires a created Linear issue and its reference. This file contains no Linear issue ID or URL. Create the issue and add the reference before merge.
I can draft the Linear issue text if needed.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx`
around lines 1 - 15, Add the required Linear issue reference to the blog post
frontmatter or content, using the created issue’s ID or URL. Update the article
identified by its title and slug, and ensure the reference is present before
merge.
| heroImagePath: "/cut-prisma-database-operations-60-percent/imgs/hero.png" | ||
| metaImagePath: "/cut-prisma-database-operations-60-percent/imgs/meta.png" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Add the image assets before publication.
These paths will produce broken hero and social-card images until the design team adds both files. Add hero.png and meta.png at the referenced paths, or defer publication.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx`
around lines 9 - 10, Add the missing hero.png and meta.png assets at the paths
referenced by heroImagePath and metaImagePath in the blog front matter before
publication, or defer publication until both files are available.
| ```typescript | ||
| // 1 query, all orders and their users loaded together | ||
| const orders = await prisma.order.findMany({ | ||
| include: { | ||
| user: true, | ||
| }, | ||
| }); | ||
| ``` | ||
|
|
||
| Prisma handles the join. One query, one round trip, regardless of how many orders exist. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
For the Prisma ORM version used by this repository, verify whether includewithoutrelationLoadStrategy: "join" guarantees a single SQL query.
💡 Result:
Yes, when you specify relationLoadStrategy: 'join', Prisma ORM is explicitly instructed to perform the operation using a single database-level SQL query [1][2][3]. Under this strategy, Prisma leverages database-specific features—such as LATERAL JOINs on PostgreSQL or correlated subqueries on MySQL—to fetch all requested data, including the relations specified in your include block, within one round trip to the database [1][3][4]. This approach uses JSON aggregation at the database level to construct the nested result structure before sending it back to the application [1][4]. It is important to note two key requirements for this behavior: 1. Feature Flag: The relationLoadStrategy option requires the relationJoins preview feature to be enabled in your schema.prisma file [4][5]. Without enabling this feature flag, the option will be rejected as an unknown argument, and Prisma will fall back to its legacy behavior (the query strategy), which executes multiple queries and merges them in the application layer [3][4]. 2. Availability: This strategy is supported for specific databases, primarily PostgreSQL, CockroachDB, and MySQL [3][4]. In summary, when relationLoadStrategy: 'join' is correctly configured, it guarantees a single SQL query execution for the relation fetch [2][6].
Citations:
- 1: https://www.prisma.io/docs/orm/v6/prisma-client/queries/relation-queries
- 2: https://www.prisma.io/docs/orm/prisma-client/queries/advanced/query-optimization-performance
- 3: https://www.prisma.io/blog/prisma-orm-now-lets-you-choose-the-best-join-strategy-preview
- 4: https://www.prisma.io/docs/orm/prisma-client/queries/relation-queries
- 5: https://github.com/prisma/prisma/releases/tag/5.8.0
- 6: https://www.prisma.io/docs/orm/v6/prisma-client/queries/query-optimization-performance
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== relevant package files =="
for f in package.json pnpm-lock.yaml package-lock.json yarn.lock bun.lockb; do
if [ -f "$f" ]; then echo "--- $f ---"; [ "$f" != "bun.lockb" ] && sed -n '1,220p' "$f" | rg -n 'prisma|`@prisma/client`|version|packages' -C 2 | head -n 200; fi
done
echo "== schema files =="
git ls-files | rg '(^|/)schema\.prisma$|prisma/' | sed -n '1,120p'
for f in $(git ls-files | rg '(^|/)schema\.prisma$'); do
echo "--- $f ---"
sed -n '1,220p' "$f" | rg -n 'previewFeatures|relationLoadStrategy|datasource|generator|model order|model user|order' -C 4
done
echo "== target MDX context =="
file="apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx"
if [ -f "$file" ]; then
wc -l "$file"
sed -n '110,150p' "$file"
else
echo "missing $file"
fi
echo "== relationLoadStrategy mentions =="
rg -n 'relationLoadStrategy|relationLoadStrategy|relationJoins|findMany|include:\s*\{|One query|Prisma handles' .Repository: prisma/web
Length of output: 50369
Do not claim include always runs one SQL query.
include avoids N+1 round trips, but relationLoadStrategy is a related query-load option here, and loadStrategy is invalid for findMany. If the example must guarantee one query, show the related single-query strategy; otherwise say it reduces queries to a fixed number without tying include directly to loadStrategy.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx`
around lines 128 - 137, Update the Prisma order-loading example around
prisma.order.findMany and its explanation so it does not claim include always
produces one SQL query. Either configure the valid relationLoadStrategy
single-query option when guaranteeing one query, or describe include as avoiding
N+1 with a fixed number of queries without asserting a single round trip.
| ## 5. Use `findUnique` for exact lookups | ||
|
|
||
| When a query matches at most one row — by `id`, by a unique email, by any unique constraint — `findUnique` is the right call. It maps to a point lookup on the unique index. `findFirst` adds an implicit scan with `LIMIT 1`. | ||
|
|
||
| ```typescript | ||
| // Scan + LIMIT 1 | ||
| const user = await prisma.user.findFirst({ | ||
| where: { id: userId }, | ||
| }); | ||
|
|
||
| // Point lookup on the unique index — faster and semantically accurate | ||
| const user = await prisma.user.findUnique({ | ||
| where: { id: userId }, | ||
| }); | ||
| ``` | ||
|
|
||
| The difference is small on tiny tables, but it compounds across high-frequency endpoints and grows with table size. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
For PostgreSQL, verify the plan for a WHERE id = ... LIMIT 1 query on a primary-key column and confirm whether it requires a sequential scan.
💡 Result:
In PostgreSQL, a query of the form WHERE id =... LIMIT 1 on a primary-key column typically uses an Index Scan (specifically an Index Unique Scan) because it is almost always the most efficient way to locate a single unique row [1]. However, it is not guaranteed to use an index in every situation [2]. PostgreSQL does not "require" a sequential scan, but the query planner may choose one if it estimates that a sequential scan will be cheaper than an index scan based on table statistics and cost parameters [2][3]. While an Index Scan is the expected behavior, a sequential scan might be chosen in specific scenarios: 1. Table Size: If a table is extremely small, the cost of accessing the index and then fetching the row from the table might be estimated as higher than simply reading the entire table sequentially [4]. 2. Planner Misestimates: In some cases, the query planner may have inaccurate statistics or outdated cost estimates regarding the data distribution, leading it to incorrectly favor a sequential scan [2][3]. 3. Query Complexity: If the query involves complex joins or additional filters that cause the planner to favor a different access path, the PK lookup might be performed differently or combined with other operations [2][4]. You can verify the chosen plan for your specific query by using the EXPLAIN command [5][6]. If you suspect the planner is making a suboptimal choice, you can analyze the query with EXPLAIN (ANALYZE, BUFFERS) to see the actual execution time and disk page access statistics [6][7]. Setting configuration parameters such as enable_seqscan to off is a troubleshooting technique to force the index usage, but it is generally discouraged for production environments as it may force the planner to choose a suboptimal plan for other queries [2][7][8].
Citations:
- 1: https://use-the-index-luke.com/sql/where-clause/the-equals-operator/primary-keys
- 2: https://www.postgresql.org/message-id/3990647.1721334167%40sss.pgh.pa.us
- 3: https://www.postgresql.org/message-id/417C23DC.1090407%40johnmeinel.com
- 4: https://stackoverflow.com/questions/77198174/why-doesnt-postgresql-look-up-by-pk-first-when-where-contains-a-condition-on
- 5: https://www.postgresql.org/docs/18/using-explain.html
- 6: https://www.postgresql.org/docs/19/sql-explain.html
- 7: https://dba.stackexchange.com/questions/289151/postgresql-chooses-to-seq-scan-huge-table-instead-of-index-lookup
- 8: https://www.postgresql.org/message-id/CAKoxK%2B6P38HkoQYXs_Kw0hOJ4sdTe7A34n%3DoY2EkspQKHxw4cQ%40mail.gmail.com
Correct the findFirst performance claim.
findUnique is the right API for unique predicates. Add context that PostgreSQL may choose an index lookup for findFirst({ where: { id } }), not a required sequential scan. Use EXPLAIN ANALYZE for performance conclusions.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx`
around lines 173 - 189, Revise the “Use findUnique for exact lookups” section
and its comparison comments to avoid claiming that findFirst necessarily
performs a scan or that findUnique is inherently faster. State that findUnique
is the semantically appropriate API for unique predicates, acknowledge
PostgreSQL may use an index lookup for findFirst({ where: { id } }), and
recommend EXPLAIN ANALYZE for validating performance conclusions.
| ```prisma | ||
| model User { | ||
| id Int @id @default(autoincrement()) | ||
| name String | ||
| totalOrders Int @default(0) | ||
| totalRevenue Float @default(0) | ||
| orders Order[] | ||
| } | ||
| ``` | ||
|
|
||
| When an order is created, update the counters in the same transaction: | ||
|
|
||
| ```typescript | ||
| await prisma.$transaction([ | ||
| prisma.order.create({ | ||
| data: { sellerId, amount, status: "PENDING" }, | ||
| }), | ||
| prisma.user.update({ | ||
| where: { id: sellerId }, | ||
| data: { | ||
| totalOrders: { increment: 1 }, | ||
| totalRevenue: { increment: amount }, | ||
| }, | ||
| }), |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
For the Prisma ORM version used by this repository, verify the PostgreSQL mappings for FloatandDecimal, and confirm the recommended type for currency totals.
💡 Result:
In Prisma ORM, the default PostgreSQL mappings for Float and Decimal scalar types are as follows [1][2]: - Prisma Float maps to PostgreSQL double precision [1][2]. - Prisma Decimal maps to PostgreSQL decimal(65,30) [1][2]. For currency totals, Prisma explicitly recommends avoiding the PostgreSQL native money type because it is integer-backed, ties values to the database server's lc_monetary locale, lacks currency context, and can lead to rounding inconsistencies [3][4][5]. Instead, the recommended approach is to use the Decimal scalar type [3][4][6]. When using Decimal, you should define a specific precision and scale (e.g., Decimal @db.Decimal(12, 2)) to suit your application's requirements [4]. Additionally, it is best practice to store the associated currency code in a separate String @db.Char(3) column to ensure data integrity [4]. Alternatively, for applications where performance and exact integer math are preferred, storing amounts as integers representing the smallest currency unit (e.g., priceCents Int) is also a supported and effective pattern [7][5].
Citations:
- 1: https://www.prisma.io/docs/orm/v6/overview/databases/postgresql
- 2: https://www.prisma.io/docs/v6/orm/overview/databases/postgresql
- 3: Recommended Prisma Schema Type for Money prisma#10160
- 4: https://developertoolkit.ai/en/cookbook/database-recipes/orm-patterns/
- 5: http://wanago.io/2024/03/04/api-nestjs-money-postgresql-prisma/
- 6: Get numeric values of Decimal data types defined in schema. prisma#23968
- 7: https://www.prisma.io/docs/orm/next/data-modeling
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== package files =="
git ls-files | rg '(^|/)(package\.json|pnpm-lock\.yaml|package-lock\.json|yarn\.lock)$' || true
echo "== relevant content around comment =="
cat -n apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx | sed -n '170,240p'
echo "== Prisma usage / versions in package files =="
rg -n '"prisma"|`@prisma/client`|prisma@|prisma:' -S --glob 'package.json' --glob 'pnpm-lock.yaml' --glob 'package-lock.json' --glob 'yarn.lock' .Repository: prisma/web
Length of output: 3750
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== package versions =="
python3 - <<'PY'
import json
from pathlib import Path
for path in Path('.').rglob('package.json'):
if any(part in {'.git','node_modules'} for part in path.parts):
continue
try:
data=json.loads(path.read_text())
except Exception as e:
continue
deps={}
for section in ('dependencies','devDependencies','peerDependencies','optionalDependencies'):
deps.update(data.get(section,{}))
hits={k:v for k,v in deps.items() if k in {'prisma','`@prisma/client`'} or 'prisma' in k.lower()}
if hits:
print(path)
for k,v in hits.items():
print(f" {k}: {v}")
PY
echo "== lockfile prisma versions =="
rg -n 'name: (prisma|`@prisma/client`)|version: |/prisma|/@prisma/client' pnpm-lock.yaml | head -80Repository: prisma/web
Length of output: 3442
Do not store revenue in Float.
totalRevenue represents money, but Prisma Float maps to PostgreSQL double precision, so repeated increments can accumulate rounding errors. Use Decimal @db.Decimal(precision, scale) and pass a decimal amount.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx`
around lines 197 - 220, Update the User model’s totalRevenue field from Float to
Decimal with an appropriate `@db.Decimal` precision and scale, and ensure the
order amount passed to the transactional increment uses a Decimal value.
Preserve the existing totalOrders and atomic prisma.$transaction update
behavior.
|
|
||
| Reading totals is now a field access on the user record instead of an aggregation query. The read goes from O(n rows) to O(1). | ||
|
|
||
| This was one of the largest single reductions in Sellary's operation count. Counters can drift if a transaction rolls back, so it's worth verifying them periodically against the actual aggregate for anything correctness-sensitive. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
For the Prisma ORM version used by this repository, verify that a failed $transaction rolls back all included writes.
💡 Result:
Yes, the Prisma ORM $transaction API is designed to ensure atomicity, meaning all included writes roll back if any operation within the transaction fails [1][2][3]. For both the array-based $transaction([]) API and the interactive (callback-based) $transaction(async (tx) => {... }) API, Prisma Client guarantees that if an error occurs or an exception is thrown, the entire transaction is automatically rolled back, ensuring the database state remains consistent [1][2][3]. Key implementation details for ensuring successful rollbacks: 1. Use the Transaction Client: When using interactive transactions, you must perform all operations using the transaction client (typically provided as the argument to the callback, e.g., tx) [4][5]. Using the main Prisma Client instance inside the callback will execute those queries outside the transaction, meaning they will not be rolled back if the transaction fails [4][5]. 2. Error Handling: If the application encounters an error, the async function must throw an exception for the transaction to automatically roll back [1][2]. You can catch these exceptions in a try-catch block to handle the failure, but the database writes will have already been rolled back by the time the exception is caught [2][3]. 3. Side Effects: Be cautious with non-database side effects (e.g., sending emails or calling external APIs) within a transaction callback. These operations are not governed by the database transaction and will not automatically "roll back" if the transaction fails [4]. Perform such side effects only after the transaction has successfully committed [4].
Citations:
- 1: https://www.prisma.io/docs/orm/prisma-client/queries/transactions
- 2: https://www.prisma.io/docs/v6/orm/prisma-client/queries/transactions
- 3: https://www.prisma.io/docs/orm/v6/prisma-client/queries/transactions
- 4: https://www.prisma.io/docs/orm/next/fundamentals/transactions
- 5: Interactive transaction is not rolling back if it's interrupted in the middle by "throw Error" prisma#11107
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate the post and inspect the relevant transaction context plus the comment locations.
post="apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx"
if [ -f "$post" ]; then
echo "== line counts =="
wc -l "$post"
echo
echo "== sections around line 180-250 =="
sed -n '180,255p' "$post" | nl -ba -v180
echo
echo "== sections around FAQ line 460-500 =="
sed -n '460,505p' "$post" | nl -ba -v460
else
echo "missing $post"
git ls-files | rg 'cut-prisma-database-operations-60-percent|\.mdx$' | head -50
fi
echo
echo "== transaction/coderound mentions in post =="
rg -n 'transaction|counter|Count|roll|drif|reconcile' "$post" || trueRepository: prisma/web
Length of output: 322
🏁 Script executed:
#!/bin/bash
set -euo pipefail
post="apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx"
echo "== line counts =="
wc -l "$post"
echo
echo "== sections around line 180-250 =="
awk 'NR>=180 && NR<=255 { printf "%d:%s\n", NR, $0 }' "$post"
echo
echo "== sections around FAQ line 460-500 =="
awk 'NR>=460 && NR<=505 { printf "%d:%s\n", NR, $0 }' "$post"
echo
echo "== transaction/coderound mentions in post =="
rg -n 'transaction|counter|Count|roll|drif|reconcile' "$post" || trueRepository: prisma/web
Length of output: 10393
Remove the rollback drift claim.
A rollback of prisma.$transaction([...]) rolls back both the order create and the counter update, so it does not create drift. List drift causes as writes that bypass counter maintenance, manual updates, migrations/incomplete migrations, or incorrect reconciliation logic. Update both the conclusion at line 226 and the FAQ answer to match.
📍 Affects 1 file
apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx#L226-L226(this comment)apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx#L485-L486
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx`
at line 226, The conclusion around the counter-verification statement and the
FAQ answer near the corresponding FAQ section must remove rollback as a drift
cause. Explain that rollbacks revert both the order creation and counter update,
and identify valid causes instead: writes bypassing counter maintenance, manual
updates, migrations or incomplete migrations, and incorrect reconciliation
logic.
| [Prisma Postgres](https://www.prisma.io/docs/postgres) includes per-query caching through a `cacheStrategy` option: | ||
|
|
||
| ```typescript | ||
| const categories = await prisma.category.findMany({ | ||
| cacheStrategy: { | ||
| ttl: 60 * 5, // serve from cache for 5 minutes | ||
| swr: 60 * 2, // serve stale for 2 more minutes while refreshing | ||
| }, | ||
| }); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
For the Prisma ORM version used by this repository, find the required Prisma Postgres or Accelerate client setup that enables cacheStrategy.
💡 Result:
To enable and use the cacheStrategy with Prisma Accelerate, you must configure your Prisma Client to use the Accelerate extension, which provides the caching capabilities [1][2]. Requirements and Setup: 1. Prisma Client Version: Ensure you are using Prisma Client version 4.16.1 or higher [1]. For projects utilizing interactive transactions, version 5.1.1 or higher is required [1]. 2. Accelerate Extension: You must install and configure the @prisma/extension-accelerate package (version 1.0.0 or higher is required; version 2.0.0+ requires Node.js 18+) [1][3]. 3. Connection String: Replace your standard database connection string with the Accelerate connection string provided by the Prisma Data Platform [1][3]. 4. Extension Initialization: Configure your Prisma Client to utilize the Accelerate extension, typically by providing the accelerateUrl via the constructor [3]. Once configured, the cacheStrategy parameter becomes available on applicable model methods (such as findMany or findUnique) [4][1]. The strategy is defined per-query using the following parameters [4][2]: - ttl (Time-to-Live): The duration in seconds for which a result is considered fresh [4][2]. - swr (Stale-While-Revalidate): The duration in seconds for which a stale result is served while the cache is revalidated in the background [4][2]. - tags (Optional): An array of strings used to manage cache invalidation [4]. Example usage: const posts = await prisma.post.findMany({ cacheStrategy: { ttl: 60, swr: 10, tags: ["example_tag"] }, }); Note that the cacheStrategy parameter is not supported for write operations (e.g., create, update) [4]. Cache invalidation for specific tags requires a paid Prisma Data Platform plan [4].
Citations:
- 1: https://www.prisma.io/docs/accelerate/getting-started
- 2: https://www.prisma.io/blog/caching-database-queries-with-prisma-accelerate
- 3: https://www.npmjs.com/package/@prisma/extension-accelerate
- 4: https://www.prisma.io/docs/accelerate/reference/api-reference
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== candidate files =="
git ls-files | rg '(^|/)(package\.json|pnpm-lock\.yaml|yarn\.lock|package-lock\.json|schema\.prisma|prisma/)' | sed -n '1,120p'
echo
echo "== prisma deps/usages =="
rg -n '"(`@prisma/client`|prisma|`@prisma/extension-accelerate`|prisma-postgres)|\.use\(|Acceleration|accelerateUrl|cacheStrategy|dataProxy|postgres:' package.json package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null || true
echo
echo "== target mdx around concern =="
sed -n '220,290p' apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx
echo
echo "== broader cacheStrategy documentation snippets in repo =="
rg -n "cacheStrategy|`@prisma/extension-accelerate`|Accelerate extension|accelerateUrl|cacheStrategy" . --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' | sed -n '1,160p'Repository: prisma/web
Length of output: 24508
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== target file line count and imports/setup area =="
wc -l apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx
sed -n '1,90p' apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx
echo
echo "== package manager version constraints =="
cat package.json
python3 - <<'PY'
import json
for f in ["package.json", "apps/blog/package.json", "apps/docs/package.json"]:
try:
data=json.load(open(f))
except Exception as e:
print(f"\n--- {f}: {e}")
continue
print(f"\n--- {f}")
for sec in ("devDependencies", "dependencies", "packageManager", "devEngines"):
vals=data.get(sec)
if vals:
print(sec, json.dumps(vals, indent=2))
PYRepository: prisma/web
Length of output: 9056
Show the Prisma Client setup that enables cacheStrategy.
cacheStrategy requires the Accelerate-backed Prisma Postgres configuration, not the plain new PrismaClient({ log: ... }) shown earlier. Include the Accelerate extension/accelerateUrl setup before this example so readers can compile related queries.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx`
around lines 263 - 271, Update the Prisma Client setup preceding the
cacheStrategy example to show the Accelerate-backed configuration, including the
required accelerateUrl and extension setup. Ensure the categories.findMany
example can compile with cacheStrategy enabled, while preserving the existing
query behavior.
| If soft deletes are the right model for your use case, a partial index limits the index to only the rows your queries actually touch: | ||
|
|
||
| ```sql | ||
| CREATE INDEX orders_active_idx ON orders (seller_id, status) | ||
| WHERE deleted_at IS NULL; | ||
| ``` | ||
|
|
||
| The index only includes active rows, so its size stays proportional to active records rather than total records ever written. In a Prisma schema, this is a `@@index` with a `where` clause parameter, applied through a raw migration. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
For the Prisma ORM version used by this repository, verify partial-index support, the required preview feature, and the @@index(..., where: ...) syntax.
💡 Result:
Prisma ORM supports partial indexes (also known as filtered indexes) [1][2]. This feature is available behind the partialIndexes preview feature flag [1][2]. To enable and use partial indexes: 1. Enable the Preview Feature: You must add partialIndexes to the previewFeatures list within your generator block in the schema.prisma file [1][2][3]: generator client { provider = "prisma-client-js" previewFeatures = ["partialIndexes"] } 2. Usage with @@index: The @@index attribute supports the where argument to define the filter condition [1][4]. Prisma supports two syntax styles for this argument [4][2]: Raw SQL: Useful for complex database-specific expressions. @@index([email], where: raw("deletedAt IS NULL")) Type-safe Object Syntax: Useful for simpler, declarative conditions. @@index([title], where: { published: true }) Partial index support is available for PostgreSQL, SQLite, SQL Server, and CockroachDB [1][2]. Note that MySQL does not support partial indexes [1]. When using introspection on a database that already contains partial indexes, Prisma will automatically add the partialIndexes preview feature to your schema and represent the predicate using the raw syntax [1].
Citations:
- 1: https://www.prisma.io/docs/orm/prisma-schema/data-model/indexes
- 2: https://www.prisma.io/changelog/2026-02-11
- 3: https://docs.prisma.io/docs/orm/prisma-schema/data-model/indexes
- 4: https://www.prisma.io/docs/orm/reference/prisma-schema-reference
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Relevant files:"
git ls-files | rg '(^|/)(package.json|pnpm-lock.yaml|package-lock.json|yarn.lock|bun.lockb|pnpm-workspace.yaml)$|schema\.prisma$|content/blog/cut-prisma-.*\.mdx$' || true
echo
echo "PRISMA package references:"
rg -n '"(`@prisma/`(client|cli))|"prisma"' package.json pnpm-lock.yaml package-lock.json yarn.lock bun.lockb apps packages 2>/dev/null | head -80 || true
echo
echo "PRISMA schema and partial index references:"
rg -n 'generator client|partialIndexes|@@index|CREATE INDEX|DELETE OR REPLACE|WHERE deleted_at|@(delete|update) (Cascade|Restrict|SetNull|SetDefault)' . -g '!node_modules' -g '!dist' -g '!build' | head -200 || true
echo
echo "Target article excerpt:"
sed -n '416,448p' apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx 2>/dev/null || trueRepository: prisma/web
Length of output: 35029
Update the partial-index guidance.
Enable the partialIndexes generator preview feature and show the Prisma schema form with @@index(..., where: ...) instead of requiring a raw migration for this predicate.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/blog/content/blog/cut-prisma-database-operations-60-percent/index.mdx`
around lines 432 - 439, Update the partial-index guidance in the soft-delete
section to show enabling Prisma’s partialIndexes generator preview feature and
defining the index with a Prisma @@index declaration using its where predicate.
Remove the statement that this requires a raw migration, while retaining the SQL
example only if it remains useful context.
Adapting my Medium post on cutting Prisma DB operations by 60% for the Prisma engineering blog.
Notes for @ankur-arch:
Linear: TBDreference in this PR?hero.pngandmeta.pngin theimgs/folder, but they are not included in this PR. They will need to be generated by the design team before this goes live.Linear: TBD by DevRel
Summary by CodeRabbit
New Content
Contributors