From e35e70541812311e48d4f7a56e7cd0aa362667ad Mon Sep 17 00:00:00 2001 From: Aidan McAlister <105178005+aidankmcalister@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:54:31 -0500 Subject: [PATCH 1/9] DC-5044 `prisma-client-js` deprecated (#7219) * `prisma-client-js` deprecated * chore: empty commit * broken link updated --- .../10-overview/03-generators.mdx | 145 +++++++++--------- .../100-prisma-schema-reference.mdx | 2 +- 2 files changed, 75 insertions(+), 72 deletions(-) diff --git a/content/200-orm/100-prisma-schema/10-overview/03-generators.mdx b/content/200-orm/100-prisma-schema/10-overview/03-generators.mdx index 843aef49f0..f66f0baf9c 100644 --- a/content/200-orm/100-prisma-schema/10-overview/03-generators.mdx +++ b/content/200-orm/100-prisma-schema/10-overview/03-generators.mdx @@ -15,79 +15,10 @@ generator client { A generator determines which assets are created when you run the `prisma generate` command. -There are two generators for Prisma Client: - -- `prisma-client` (recommended): Newer and more flexible version of `prisma-client-js` with ESM support; it outputs plain TypeScript code and _requires_ a custom `output` path (read more about it [here](https://www.prisma.io/blog/why-prisma-orm-generates-code-into-node-modules-and-why-it-ll-change)) -- `prisma-client-js`: Generates Prisma Client into `node_modules` +The default generator for Prisma Client is `prisma-client`, which outputs plain TypeScript code and _requires_ a custom `output` path (read more about it [here](https://www.prisma.io/blog/why-prisma-orm-generates-code-into-node-modules-and-why-it-ll-change)). Alternatively, you can configure any npm package that complies with our generator specification. -## `prisma-client-js` - -The `prisma-client-js` is the default generator for Prisma ORM 6.X versions and before. It requires the `@prisma/client` npm package and generates Prisma Client into `node_modules`. - -### Field reference - -The generator for Prisma's JavaScript Client accepts multiple additional properties: - -- `previewFeatures`: [Preview features](/orm/reference/preview-features) to include -- `binaryTargets`: Engine binary targets for `prisma-client-js` (for example, `debian-openssl-1.1.x` if you are deploying to Ubuntu 18+, or `native` if you are working locally) - -```prisma -generator client { - provider = "prisma-client-js" - previewFeatures = ["sample-preview-feature"] - binaryTargets = ["debian-openssl-1.1.x"] // defaults to `"native"` -} -``` - -### Binary targets - -:::note - -As of [v6.16.0](https://pris.ly/release/6.16.0), Prisma ORM can be used without Rust engines in production applications. Learn more [here](/orm/prisma-client/setup-and-configuration/no-rust-engine). - -**When enabled, your Prisma Client will be generated without a Rust-based query engine binary**: - -```prisma -generator client { - provider = "prisma-client-js" // or "prisma-client" - output = "../src/generated/prisma" - engineType = "client" // no Rust engine -} -``` - -Note that [driver adapters](/orm/overview/databases/database-drivers#driver-adapters) are required if you want to use Prisma ORM without Rust engines. - -When using Prisma ORM without Rust, the `binaryTargets` field is obsolete and not needed. - -You can [read about the performance and DX improvements](https://www.prisma.io/blog/prisma-orm-without-rust-latest-performance-benchmarks) of this change on our blog. - -::: - -The `prisma-client-js` generator uses several [engines](https://github.com/prisma/prisma-engines). Engines are implemented in Rust and are used by Prisma Client in the form of executable, platform-dependent engine files. Depending on which platform you are executing your code on, you need the correct file. "Binary targets" are used to define which files should be present for the target platform(s). - -The correct file is particularly important when [deploying](/orm/prisma-client/deployment/deploy-prisma) your application to production, which often differs from your local development environment. - -#### The `native` binary target - -The `native` binary target is special. It doesn't map to a concrete operating system. Instead, when `native` is specified in `binaryTargets`, Prisma Client detects the _current_ operating system and automatically specifies the correct binary target for it. - -As an example, assume you're running **macOS** and you specify the following generator: - -```prisma file=prisma/schema.prisma -generator client { - provider = "prisma-client-js" - binaryTargets = ["native"] -} -``` - -In that case, Prisma Client detects your operating system and finds the right binary file for it based on the [list of supported operating systems](/orm/reference/prisma-schema-reference#binarytargets-options) . -If you use macOS Intel x86 (`darwin`), then the binary file that was compiled for `darwin` will be selected. -If you use macOS ARM64 (`darwin-arm64`), then the binary file that was compiled for `darwin-arm64` will be selected. - -> **Note**: The `native` binary target is the default. You can set it explicitly if you wish to include additional [binary targets](/orm/reference/prisma-schema-reference#binarytargets-options) for deployment to different environments. - ## `prisma-client` The new `prisma-client` generator offers greater control and flexibility when using Prisma ORM across different JavaScript environments (such as ESM, Bun, Deno, ...). @@ -104,7 +35,7 @@ Here are the main differences compared to `prisma-client-js`: - More flexible thanks to additional [fields](#field-reference) - Outputs plain TypeScript that's bundled just like the rest of your application code -The `prisma-client` generator has been Generally Available since [v6.16.0](https://pris.ly/releases/6.16.0) will become the new default with Prisma ORM v7. +The `prisma-client` generator has been Generally Available since [v6.16.0](https://pris.ly/releases/6.16.0) and is the default generator as of Prisma ORM v7. ### Getting started @@ -396,6 +327,78 @@ To see what the new `prisma-client` generator looks like in practice, check out | [`bun`](https://github.com/prisma/prisma-examples/tree/latest/generator-prisma-client/deno-deploy) | None | None | Deno 2 | n/a | | [`deno`](https://github.com/prisma/prisma-examples/tree/latest/generator-prisma-client/deno-deploy) | None | None | Deno 2 | n/a | +## `prisma-client-js` (Deprecated) + +:::warning Deprecated + +The `prisma-client-js` generator is **deprecated as of Prisma 7**. It was the default generator for Prisma ORM 6.X and earlier versions. We recommend migrating to [`prisma-client`](#prisma-client) for new projects and updating existing projects when possible. + +::: + +The `prisma-client-js` generator requires the `@prisma/client` npm package and generates Prisma Client into `node_modules`. + +### Field reference + +The generator for Prisma's JavaScript Client accepts multiple additional properties: + +- `previewFeatures`: [Preview features](/orm/reference/preview-features) to include +- `binaryTargets`: Engine binary targets for `prisma-client-js` (for example, `debian-openssl-1.1.x` if you are deploying to Ubuntu 18+, or `native` if you are working locally) + +```prisma +generator client { + provider = "prisma-client-js" + previewFeatures = ["sample-preview-feature"] + binaryTargets = ["debian-openssl-1.1.x"] // defaults to `"native"` +} +``` + +### Binary targets + +:::note + +As of [v6.16.0](https://pris.ly/release/6.16.0), Prisma ORM can be used without Rust engines in production applications. Learn more [here](/orm/prisma-client/setup-and-configuration/no-rust-engine). + +**When enabled, your Prisma Client will be generated without a Rust-based query engine binary**: + +```prisma +generator client { + provider = "prisma-client-js" // or "prisma-client" + output = "../src/generated/prisma" + engineType = "client" // no Rust engine +} +``` + +Note that [driver adapters](/orm/overview/databases/database-drivers#driver-adapters) are required if you want to use Prisma ORM without Rust engines. + +When using Prisma ORM without Rust, the `binaryTargets` field is obsolete and not needed. + +You can [read about the performance and DX improvements](https://www.prisma.io/blog/prisma-orm-without-rust-latest-performance-benchmarks) of this change on our blog. + +::: + +The `prisma-client-js` generator uses several [engines](https://github.com/prisma/prisma-engines). Engines are implemented in Rust and are used by Prisma Client in the form of executable, platform-dependent engine files. Depending on which platform you are executing your code on, you need the correct file. "Binary targets" are used to define which files should be present for the target platform(s). + +The correct file is particularly important when [deploying](/orm/prisma-client/deployment/deploy-prisma) your application to production, which often differs from your local development environment. + +#### The `native` binary target + +The `native` binary target is special. It doesn't map to a concrete operating system. Instead, when `native` is specified in `binaryTargets`, Prisma Client detects the _current_ operating system and automatically specifies the correct binary target for it. + +As an example, assume you're running **macOS** and you specify the following generator: + +```prisma file=prisma/schema.prisma +generator client { + provider = "prisma-client-js" + binaryTargets = ["native"] +} +``` + +In that case, Prisma Client detects your operating system and finds the right binary file for it based on the [list of supported operating systems](/orm/reference/prisma-schema-reference#binarytargets-options) . +If you use macOS Intel x86 (`darwin`), then the binary file that was compiled for `darwin` will be selected. +If you use macOS ARM64 (`darwin-arm64`), then the binary file that was compiled for `darwin-arm64` will be selected. + +> **Note**: The `native` binary target is the default. You can set it explicitly if you wish to include additional [binary targets](/orm/reference/prisma-schema-reference#binarytargets-options) for deployment to different environments. + ## Community generators :::note diff --git a/content/200-orm/500-reference/100-prisma-schema-reference.mdx b/content/200-orm/500-reference/100-prisma-schema-reference.mdx index 4170e7843e..2ec6a8f533 100644 --- a/content/200-orm/500-reference/100-prisma-schema-reference.mdx +++ b/content/200-orm/500-reference/100-prisma-schema-reference.mdx @@ -161,7 +161,7 @@ Defines a [generator](/orm/prisma-schema/overview/generators) in the Prisma sche ### Fields for `prisma-client-js` provider -This is the default generator for Prisma ORM 6.x and earlier versions. Learn more about [generators](/orm/prisma-schema/overview/generators#prisma-client-js). +This is the default generator for Prisma ORM 6.x and earlier versions. Learn more about [generators](/orm/prisma-schema/overview/generators#prisma-client-js-deprecated). A `generator` block accepts the following fields: From f8c32d118f4002b6f93ada0fa00a23189462234c Mon Sep 17 00:00:00 2001 From: Aidan McAlister <105178005+aidankmcalister@users.noreply.github.com> Date: Wed, 5 Nov 2025 13:42:13 -0500 Subject: [PATCH 2/9] DC-5040 Env Vars via Config (#7227) * added env vars section to various pages * minor coderabbit updates * verbose removed * test removed redirect list * removed quickstart addition * converted quickstarts back --- .coderabbit.yaml | 2 ++ .github/workflows/lychee.yml | 8 ++--- .../010-generating-prisma-client.mdx | 29 +++++++++++++++++ .../325-prisma-config-reference.mdx | 31 ++++++++++++++++++- 4 files changed, 64 insertions(+), 6 deletions(-) diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 32aff8c11a..873a29ff16 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -1,6 +1,7 @@ # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json # yaml template to refer to https://docs.coderabbit.ai/reference/yaml-template#enterprise language: "en-US" +tone_instructions: "You are a principal engineer with natural teaching abilities. You detect issues and clearly explain why." reviews: collapse_walkthrough: false profile: "chill" @@ -14,6 +15,7 @@ reviews: auto_review: enabled: true drafts: false + base_branches: [".*"] finishing_touches: docstrings: enabled: false diff --git a/.github/workflows/lychee.yml b/.github/workflows/lychee.yml index 72cf3fa499..0b705f533c 100644 --- a/.github/workflows/lychee.yml +++ b/.github/workflows/lychee.yml @@ -25,7 +25,6 @@ jobs: --cache --cache-exclude-status 429,500,502,503,504 --max-cache-age 5m - --verbose --no-progress --accept 200,201,204,304,403,429 --timeout 20 @@ -50,7 +49,6 @@ jobs: args: > --cache --max-cache-age 5m - --verbose --no-progress --accept 200,201,204,304,403,429 --cache-exclude-status 429,500,502,503,504 @@ -79,8 +77,8 @@ jobs: fi if [ -n "$REPORT_FILE" ]; then - # Read the original output - ORIGINAL=$(cat "$REPORT_FILE") + # Read the original output and remove everything after 'Redirects per input' + ORIGINAL=$(cat "$REPORT_FILE" | sed '/^##* Redirects per input/,$d') # Create formatted output cat > lychee/formatted.md << EOF @@ -92,7 +90,7 @@ jobs: EOF - # Append the original content with title replacement + # Append the cleaned content with title replacement echo "$ORIGINAL" | sed 's/^# Summary$//' | sed 's/^## Summary$//' >> lychee/formatted.md fi diff --git a/content/200-orm/200-prisma-client/000-setup-and-configuration/010-generating-prisma-client.mdx b/content/200-orm/200-prisma-client/000-setup-and-configuration/010-generating-prisma-client.mdx index fa86ed9fa5..8e7d257bf2 100644 --- a/content/200-orm/200-prisma-client/000-setup-and-configuration/010-generating-prisma-client.mdx +++ b/content/200-orm/200-prisma-client/000-setup-and-configuration/010-generating-prisma-client.mdx @@ -124,6 +124,35 @@ For improved compatibility with ECMAScript modules (ESM) and to ensure consisten ::: +## Loading environment variables + +To load environment variables in your Prisma application, you can use the `prisma.config.ts` file along with the `env` helper from `prisma/config`. This approach provides better type safety and configuration management. + +1. First, install the required dependency: + + ```bash + npm install dotenv --save-dev + ``` + +2. Create a `.env` file in your project root (if it doesn't exist) and add your database connection string: + + ```env + DATABASE_URL="your_database_connection_string_here" + ``` + +3. Update your `prisma.config.ts` file in your project root: + + ```ts + import "dotenv/config"; + import { defineConfig, env } from "prisma/config"; + + export default defineConfig({ + datasource: { + url: env("DATABASE_URL"), + }, + }); + ``` + ## The `@prisma/client` npm package The `@prisma/client` npm package consists of two key parts: diff --git a/content/200-orm/500-reference/325-prisma-config-reference.mdx b/content/200-orm/500-reference/325-prisma-config-reference.mdx index 2ecf7bfdaf..d7a5492238 100644 --- a/content/200-orm/500-reference/325-prisma-config-reference.mdx +++ b/content/200-orm/500-reference/325-prisma-config-reference.mdx @@ -597,4 +597,33 @@ You can specify a custom location for your config file when running Prisma CLI c ```terminal prisma validate --config ./path/to/myconfig.ts -``` \ No newline at end of file +``` + +## Loading environment variables + +To load environment variables in your Prisma application, you can use the `prisma.config.ts` file along with the `env` helper from `prisma/config`. This approach provides better type safety and configuration management. + +1. First, install the required dependency: + + ```bash + npm install dotenv --save-dev + ``` + +2. Create a `.env` file in your project root (if it doesn't exist) and add your database connection string: + + ```env + DATABASE_URL="your_database_connection_string_here" + ``` + +3. Update your `prisma.config.ts` file in your project root: + + ```ts + import "dotenv/config"; + import { defineConfig, env } from "prisma/config"; + + export default defineConfig({ + datasource: { + url: env("DATABASE_URL"), + }, + }); + ``` \ No newline at end of file From 87eba65abc71b017703b6d0ef0e16076578db5c8 Mon Sep 17 00:00:00 2001 From: Aidan McAlister <105178005+aidankmcalister@users.noreply.github.com> Date: Wed, 5 Nov 2025 13:42:19 -0500 Subject: [PATCH 3/9] urls deprecated (#7226) --- .../10-overview/02-data-sources.mdx | 4 ++++ .../500-reference/100-prisma-schema-reference.mdx | 10 +++++++--- .../500-reference/325-prisma-config-reference.mdx | 14 ++++++++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/content/200-orm/100-prisma-schema/10-overview/02-data-sources.mdx b/content/200-orm/100-prisma-schema/10-overview/02-data-sources.mdx index 862dea32ac..efbb38773b 100644 --- a/content/200-orm/100-prisma-schema/10-overview/02-data-sources.mdx +++ b/content/200-orm/100-prisma-schema/10-overview/02-data-sources.mdx @@ -6,6 +6,10 @@ metaDescription: 'Data sources enable Prisma to connect to your database. This p A data source determines how Prisma ORM connects to your database, and is represented by the [`datasource`](/orm/reference/prisma-schema-reference#datasource) block in the Prisma schema. The following data source uses the `postgresql` provider and includes a connection URL: +::::note +As of Prisma ORM v7, the `url`, `directUrl`, and `shadowDatabaseUrl` fields in the Prisma schema `datasource` block are deprecated. Configure these fields in [Prisma Config](/orm/reference/prisma-config-reference) instead. +:::: + ```prisma datasource db { provider = "postgresql" diff --git a/content/200-orm/500-reference/100-prisma-schema-reference.mdx b/content/200-orm/500-reference/100-prisma-schema-reference.mdx index 2ec6a8f533..ec555ae819 100644 --- a/content/200-orm/500-reference/100-prisma-schema-reference.mdx +++ b/content/200-orm/500-reference/100-prisma-schema-reference.mdx @@ -18,12 +18,16 @@ A `datasource` block accepts the following fields: | Name | Required | Type | Description | | ------------------- | -------- | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `provider` | **Yes** | String (`postgresql`, `mysql`, `sqlite`, `sqlserver`, `mongodb`, `cockroachdb`) | Describes which data source connectors to use. | -| `url` | **Yes** | String (URL) | Connection URL including authentication info. Most connectors use [the syntax provided by the database](/orm/reference/connection-urls#format). | -| `shadowDatabaseUrl` | No | String (URL) | Connection URL to the shadow database used by Prisma Migrate. Allows you to use a cloud-hosted database as the shadow database. | -| `directUrl` | No | String (URL) | Connection URL for direct connection to the database.

If you use a connection pooler URL in the `url` argument (for example, if you use [Prisma Accelerate](/accelerate) or pgBouncer), Prisma CLI commands that require a direct connection to the database use the URL in the `directUrl` argument.

The `directUrl` property is supported by Prisma Studio from version 5.1.0 upwards.

The `directUrl` property is not needed when using [Prisma Postgres](/postgres) database. | +| `url` | **Yes** | String (URL) | **Deprecated in Prisma ORM v7.** Configure the connection URL in Prisma Config instead: see [`datasource.url`](/orm/reference/prisma-config-reference#datasourceurl). Existing schemas continue to work, but you should migrate to Prisma Config. | +| `shadowDatabaseUrl` | No | String (URL) | **Deprecated in Prisma ORM v7.** Configure the shadow database URL in Prisma Config instead: see [`datasource.shadowDatabaseUrl`](/orm/reference/prisma-config-reference#datasourceshadowdatabaseurl). | +| `directUrl` | No | String (URL) | **Deprecated in Prisma ORM v7.** Configure the direct connection URL in Prisma Config instead: see [`datasource.directUrl`](/orm/reference/prisma-config-reference#datasourcedirecturl). | | `relationMode` | No | String (`foreignKeys`, `prisma`) | Sets whether [referential integrity](/orm/prisma-schema/data-model/relations/relation-mode) is enforced by foreign keys in the database or emulated in the Prisma Client.

In preview in versions 3.1.1 and later. The field is named `relationMode` in versions 4.5.0 and later, and was previously named `referentialIntegrity`. | | `extensions` | No | List of strings (PostgreSQL extension names) | Allows you to [represent PostgreSQL extensions in your schema](/orm/prisma-schema/postgresql-extensions). Available in preview for PostgreSQL only in Prisma ORM versions 4.5.0 and later. | +::::note +As of Prisma ORM v7, the `url`, `directUrl`, and `shadowDatabaseUrl` fields in the Prisma schema `datasource` block are deprecated. Configure these fields in [Prisma Config](/orm/reference/prisma-config-reference) instead. +:::: + The following providers are available: - [`sqlite`](/orm/overview/databases/sqlite) diff --git a/content/200-orm/500-reference/325-prisma-config-reference.mdx b/content/200-orm/500-reference/325-prisma-config-reference.mdx index d7a5492238..c81cd8e241 100644 --- a/content/200-orm/500-reference/325-prisma-config-reference.mdx +++ b/content/200-orm/500-reference/325-prisma-config-reference.mdx @@ -374,6 +374,10 @@ export default defineConfig({ Connection URL including authentication info. Most connectors use [the syntax provided by the database](/orm/reference/connection-urls#format). +:::note +Replaces the deprecated `url` field in the Prisma schema `datasource` block (Prisma ORM v7 and later). +::: + | Property | Type | Required | Default | | -------- | ------------------ | -------- | ----------------- | | `datasource.url` | `string` | Yes | `''` | @@ -381,9 +385,12 @@ Connection URL including authentication info. Most connectors use [the syntax pr ### `datasource.shadowDatabaseUrl` - Connection URL to the shadow database used by Prisma Migrate. Allows you to use a cloud-hosted database as the shadow database +:::note +Replaces the deprecated `shadowDatabaseUrl` field in the Prisma schema `datasource` block (Prisma ORM v7 and later). +::: + | Property | Type | Required | Default | | -------- | ------------------ | -------- | ----------------- | | `datasource.shadowDatabaseUrl` | `string` | No | `''` | @@ -391,9 +398,12 @@ Connection URL to the shadow database used by Prisma Migrate. Allows you to use ### `datasource.directUrl` - Connection URL for direct connection to the database. +:::note +Replaces the deprecated `directUrl` field in the Prisma schema `datasource` block (Prisma ORM v7 and later). +::: + If you use a connection pooler URL in the `url` argument (for example, if you use [Prisma Accelerate](/accelerate) or pgBouncer), Prisma CLI commands that require a direct connection to the database use the URL in the `directUrl` argument.

The `directUrl` property is supported by Prisma Studio from version 5.1.0 upwards.

The `directUrl` property is not needed when using [Prisma Postgres](/postgres) database. | Property | Type | Required | Default | From ac89f6aee1a5054eb923551e2268528444d34980 Mon Sep 17 00:00:00 2001 From: Aidan McAlister <105178005+aidankmcalister@users.noreply.github.com> Date: Fri, 7 Nov 2025 09:00:11 -0500 Subject: [PATCH 4/9] minimum version uodated (#7234) --- .../200-orm/500-reference/400-system-requirements.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/content/200-orm/500-reference/400-system-requirements.mdx b/content/200-orm/500-reference/400-system-requirements.mdx index 6226c4d734..fcc713e2d2 100644 --- a/content/200-orm/500-reference/400-system-requirements.mdx +++ b/content/200-orm/500-reference/400-system-requirements.mdx @@ -17,8 +17,8 @@ The latest version of Prisma ORM requires the following software: | Tool | Minimum required version | | :-------------------- | :----------------------- | -| Node.js | 18.8 / 20.9 / 22.11 | -| TypeScript (optional) | 5.1.X | +| Node.js | 20.19.0+ | +| TypeScript (optional) | 5.4+ | | Yarn (optional) | 1.19.2 | @@ -33,14 +33,14 @@ See also: [Supported database versions](/orm/reference/supported-databases)
Expand for earlier versions -### Prisma ORM v5 +### Prisma ORM v6 -Prisma ORM v5 requires the following software: +Prisma ORM v6 requires the following software: | | Minimum required version | | :-------------------- | :----------------------- | | Node.js | 16.13 / 18.X / 20.X | -| TypeScript (optional) | 4.7.X | +| TypeScript (optional) | 4.7+ | | Yarn (optional) | 1.19.2 |
From 3bf085da615592a4a153d34bdbffeed66547dc56 Mon Sep 17 00:00:00 2001 From: Aidan McAlister <105178005+aidankmcalister@users.noreply.github.com> Date: Fri, 7 Nov 2025 09:00:22 -0500 Subject: [PATCH 5/9] DC-5043 Middleware removed from docs (#7233) * middleware deleted * more middleware removed * more middleware removed * coderabbit changes --- .../100-query-optimization-performance.mdx | 2 - .../300-client-extensions/120-query.mdx | 19 +- .../100-soft-delete-middleware.mdx | 681 ------------------ .../500-middleware/200-logging-middleware.mdx | 90 --- .../300-session-data-middleware.mdx | 72 -- .../500-middleware/index.mdx | 193 ----- .../300-client-extensions/index.mdx | 26 - .../250-opentelemetry-tracing.mdx | 18 +- .../050-prisma-client-reference.mdx | 57 -- .../050-client-preview-features.mdx | 21 +- .../800-more/350-ai-tools/100-cursor.mdx | 4 - .../800-more/350-ai-tools/300-windsurf.mdx | 4 - .../350-ai-tools/400-github-copilot.mdx | 1 - .../400-query-optimization/100-setup.mdx | 12 +- .../300-accelerate/200-getting-started.mdx | 8 +- content/700-optimize/200-getting-started.mdx | 8 +- 16 files changed, 18 insertions(+), 1198 deletions(-) delete mode 100644 content/200-orm/200-prisma-client/300-client-extensions/500-middleware/100-soft-delete-middleware.mdx delete mode 100644 content/200-orm/200-prisma-client/300-client-extensions/500-middleware/200-logging-middleware.mdx delete mode 100644 content/200-orm/200-prisma-client/300-client-extensions/500-middleware/300-session-data-middleware.mdx delete mode 100644 content/200-orm/200-prisma-client/300-client-extensions/500-middleware/index.mdx diff --git a/content/200-orm/200-prisma-client/100-queries/100-query-optimization-performance.mdx b/content/200-orm/200-prisma-client/100-queries/100-query-optimization-performance.mdx index 06593ad5e8..e4354e9313 100644 --- a/content/200-orm/200-prisma-client/100-queries/100-query-optimization-performance.mdx +++ b/content/200-orm/200-prisma-client/100-queries/100-query-optimization-performance.mdx @@ -42,8 +42,6 @@ To get started, follow the [integration guide](/optimize/getting-started) and ad You can also [log query events at the client level](/orm/prisma-client/observability-and-logging/logging#event-based-logging) to view the generated queries, their parameters, and execution times. -If you are particularly focused on monitoring query duration, consider using [logging middleware](/orm/prisma-client/client-extensions/middleware/logging-middleware). - ::: ## Using bulk queries diff --git a/content/200-orm/200-prisma-client/300-client-extensions/120-query.mdx b/content/200-orm/200-prisma-client/300-client-extensions/120-query.mdx index 733c03041b..9c408e7620 100644 --- a/content/200-orm/200-prisma-client/300-client-extensions/120-query.mdx +++ b/content/200-orm/200-prisma-client/300-client-extensions/120-query.mdx @@ -15,7 +15,7 @@ Prisma Client extensions are Generally Available from versions 4.16.0 and later. You can use the `query` [Prisma Client extensions](/orm/prisma-client/client-extensions) component type to hook into the query life-cycle and modify an incoming query or its result. -You can use Prisma Client extensions `query` component to create independent clients. This provides an alternative to [middlewares](/orm/prisma-client/client-extensions/middleware). You can bind one client to a specific filter or user, and another client to another filter or user. For example, you might do this to get [user isolation](/orm/prisma-client/client-extensions#extended-clients) in a row-level security (RLS) extension. In addition, unlike middlewares the `query` extension component gives you end-to-end type safety. [Learn more about `query` extensions versus middlewares](#query-extensions-versus-middlewares). +You can use Prisma Client extensions `query` component to create independent clients with customized behavior. You can bind one client to a specific filter or user, and another client to another filter or user. For example, you might do this to get [user isolation](/orm/prisma-client/client-extensions#extended-clients) in a row-level security (RLS) extension. The `query` extension component provides end-to-end type safety for all your custom queries. @@ -283,20 +283,3 @@ const transactionExtension = Prisma.defineExtension((prisma) => const prisma = new PrismaClient().$extends(transactionExtension) ``` -## Query extensions versus middlewares - -You can use query extensions or [middlewares](/orm/prisma-client/client-extensions/middleware) to hook into the query life-cycle and modify an incoming query or its result. Client extensions and middlewares differ in the following ways: - -- Middlewares always apply globally to the same client. Client extensions are isolated, unless you deliberately combine them. [Learn more about client extensions](/orm/prisma-client/client-extensions#about-prisma-client-extensions). - - For example, in a row-level security (RLS) scenario, you can keep each user in an entirely separate client. With middlewares, all users are active in the same client. -- During application execution, with extensions you can choose from one or more extended clients, or the standard Prisma Client. With middlewares, you cannot choose which client to use, because there is only one global client. -- Extensions benefit from end-to-end type safety and inference, but middlewares don't. - -You can use Prisma Client extensions in all scenarios where middlewares can be used. - -### If you use the `query` extension component and middlewares - -If you use the `query` extension component and middlewares in your project, then the following rules and priorities apply: - -- In your application code, you must declare all your middlewares on the main Prisma Client instance. You cannot declare them on an extended client. -- In situations where middlewares and extensions with a `query` component execute, Prisma Client executes the middlewares before it executes the extensions with the `query` component. Prisma Client executes the individual middlewares and extensions in the order in which you instantiated them with `$use` or `$extends`. diff --git a/content/200-orm/200-prisma-client/300-client-extensions/500-middleware/100-soft-delete-middleware.mdx b/content/200-orm/200-prisma-client/300-client-extensions/500-middleware/100-soft-delete-middleware.mdx deleted file mode 100644 index cdfe0ac784..0000000000 --- a/content/200-orm/200-prisma-client/300-client-extensions/500-middleware/100-soft-delete-middleware.mdx +++ /dev/null @@ -1,681 +0,0 @@ ---- -title: 'Middleware sample: soft delete' -metaTitle: 'Middleware sample: soft delete (Reference)' -metaDescription: 'How to use middleware to intercept deletes and set a field value instead of deleting the record.' -toc_max_heading_level: 4 ---- - - - -The following sample uses [middleware](/orm/prisma-client/client-extensions/middleware) to perform a **soft delete**. Soft delete means that a record is **marked as deleted** by changing a field like `deleted` to `true` rather than actually being removed from the database. Reasons to use a soft delete include: - -- Regulatory requirements that mean you have to keep data for a certain amount of time -- 'Trash' / 'bin' functionality that allows users to restore content that was deleted - - - -**Note:** This page demonstrates a sample use of middleware. We do not intend the sample to be a fully functional soft delete feature and it does not cover all edge cases. For example, the middleware does not work with nested writes and therefore won't capture situations where you use `delete` or `deleteMany` as an option e.g. in an `update` query. - - - -This sample uses the following schema - note the `deleted` field on the `Post` model: - -```prisma highlight=28;normal -datasource db { - provider = "postgresql" - url = env("DATABASE_URL") -} - -generator client { - provider = "prisma-client-js" -} - -model User { - id Int @id @default(autoincrement()) - name String? - email String @unique - posts Post[] - followers User[] @relation("UserToUser") - user User? @relation("UserToUser", fields: [userId], references: [id]) - userId Int? -} - -model Post { - id Int @id @default(autoincrement()) - title String - content String? - user User? @relation(fields: [userId], references: [id]) - userId Int? - tags Tag[] - views Int @default(0) - //highlight-next-line - deleted Boolean @default(false) -} - -model Category { - id Int @id @default(autoincrement()) - parentCategory Category? @relation("CategoryToCategory", fields: [categoryId], references: [id]) - category Category[] @relation("CategoryToCategory") - categoryId Int? -} - -model Tag { - tagName String @id // Must be unique - posts Post[] -} -``` - - - -
-Questions answered in this page - -- How to implement soft delete middleware? -- How to block reads/updates of deleted records? -- What are trade-offs of middleware-based soft delete? - -
- -## Step 1: Store status of record - -Add a field named `deleted` to the `Post` model. You can choose between two field types depending on your requirements: - -- `Boolean` with a default value of `false`: - - ```prisma highlight=4;normal - model Post { - id Int @id @default(autoincrement()) - ... - //highlight-next-line - deleted Boolean @default(false) - } - ``` - -- Create a nullable `DateTime` field so that you know exactly _when_ a record was marked as deleted - `NULL` indicates that a record has not been deleted. In some cases, storing when a record was removed may be a regulatory requirement: - - ```prisma highlight=4;normal - model Post { - id Int @id @default(autoincrement()) - ... - //highlight-next-line - deleted DateTime? - } - ``` - -> **Note**: Using two separate fields (`isDeleted` and `deletedDate`) may result in these two fields becoming out of sync - for example, a record may be marked as deleted but have no associated date.) - -This sample uses a `Boolean` field type for simplicity. - -## Step 2: Soft delete middleware - -Add a middleware that performs the following tasks: - -- Intercepts `delete()` and `deleteMany()` queries for the `Post` model -- Changes the `params.action` to `update` and `updateMany` respectively -- Introduces a `data` argument and sets `{ deleted: true }`, preserving other filter arguments if they exist - -Run the following sample to test the soft delete middleware: - -```ts -import { PrismaClient } from '@prisma/client' - -const prisma = new PrismaClient({}) - -async function main() { - /***********************************/ - /* SOFT DELETE MIDDLEWARE */ - /***********************************/ - - prisma.$use(async (params, next) => { - // Check incoming query type - if (params.model == 'Post') { - if (params.action == 'delete') { - // Delete queries - // Change action to an update - params.action = 'update' - params.args['data'] = { deleted: true } - } - if (params.action == 'deleteMany') { - // Delete many queries - params.action = 'updateMany' - if (params.args.data != undefined) { - params.args.data['deleted'] = true - } else { - params.args['data'] = { deleted: true } - } - } - } - return next(params) - }) - - /***********************************/ - /* TEST */ - /***********************************/ - - const titles = [ - { title: 'How to create soft delete middleware' }, - { title: 'How to install Prisma' }, - { title: 'How to update a record' }, - ] - - console.log('\u001b[1;34mSTARTING SOFT DELETE TEST \u001b[0m') - console.log('\u001b[1;34m#################################### \u001b[0m') - - let i = 0 - let posts = new Array() - - // Create 3 new posts with a randomly assigned title each time - for (i == 0; i < 3; i++) { - const createPostOperation = prisma.post.create({ - data: titles[Math.floor(Math.random() * titles.length)], - }) - posts.push(createPostOperation) - } - - var postsCreated = await prisma.$transaction(posts) - - console.log( - 'Posts created with IDs: ' + - '\u001b[1;32m' + - postsCreated.map((x) => x.id) + - '\u001b[0m' - ) - - // Delete the first post from the array - const deletePost = await prisma.post.delete({ - where: { - id: postsCreated[0].id, // Random ID - }, - }) - - // Delete the 2nd two posts - const deleteManyPosts = await prisma.post.deleteMany({ - where: { - id: { - in: [postsCreated[1].id, postsCreated[2].id], - }, - }, - }) - - const getPosts = await prisma.post.findMany({ - where: { - id: { - in: postsCreated.map((x) => x.id), - }, - }, - }) - - console.log() - - console.log( - 'Deleted post with ID: ' + '\u001b[1;32m' + deletePost.id + '\u001b[0m' - ) - console.log( - 'Deleted posts with IDs: ' + - '\u001b[1;32m' + - [postsCreated[1].id + ',' + postsCreated[2].id] + - '\u001b[0m' - ) - console.log() - console.log( - 'Are the posts still available?: ' + - (getPosts.length == 3 - ? '\u001b[1;32m' + 'Yes!' + '\u001b[0m' - : '\u001b[1;31m' + 'No!' + '\u001b[0m') - ) - console.log() - console.log('\u001b[1;34m#################################### \u001b[0m') - // 4. Count ALL posts - const f = await prisma.post.findMany({}) - console.log('Number of posts: ' + '\u001b[1;32m' + f.length + '\u001b[0m') - - // 5. Count DELETED posts - const r = await prisma.post.findMany({ - where: { - deleted: true, - }, - }) - console.log( - 'Number of SOFT deleted posts: ' + '\u001b[1;32m' + r.length + '\u001b[0m' - ) -} - -main() -``` - -The sample outputs the following: - -```no-lines -STARTING SOFT DELETE TEST -#################################### -Posts created with IDs: 587,588,589 - -Deleted post with ID: 587 -Deleted posts with IDs: 588,589 - -Are the posts still available?: Yes! - -#################################### -``` - -:::tip - -Comment out the middleware to see the message change. - -::: - -✔ Pros of this approach to soft delete include: - -- Soft delete happens at data access level, which means that you cannot delete records unless you use raw SQL - -✘ Cons of this approach to soft delete include: - -- Content can still be read and updated unless you explicitly filter by `where: { deleted: false }` - in a large project with a lot of queries, there is a risk that soft deleted content will still be displayed -- You can still use raw SQL to delete records - -:::tip - -You can create rules or triggers ([MySQL](https://dev.mysql.com/doc/refman/8.0/en/trigger-syntax.html) and [PostgreSQL](https://www.postgresql.org/docs/8.1/rules-update.html)) at a database level to prevent records from being deleted. - -::: - -## Step 3: Optionally prevent read/update of soft deleted records - -In step 2, we implemented middleware that prevents `Post` records from being deleted. However, you can still read and update deleted records. This step explores two ways to prevent the reading and updating of deleted records. - -> **Note**: These options are just ideas with pros and cons, you may choose to do something entirely different. - -### Option 1: Implement filters in your own application code - -In this option: - -- Prisma Client middleware is responsible for preventing records from being deleted -- Your own application code (which could be a GraphQL API, a REST API, a module) is responsible for filtering out deleted posts where necessary (`{ where: { deleted: false } }`) when reading and updating data - for example, the `getPost` GraphQL resolver never returns a deleted post - -✔ Pros of this approach to soft delete include: - -- No change to Prisma Client's create/update queries - you can easily request deleted records if you need them -- Modifying queries in middleware can have some unintended consequences, such as changing query return types (see option 2) - -✘ Cons of this approach to soft delete include: - -- Logic relating to soft delete maintained in two different places -- If your API surface is very large and maintained by multiple contributors, it may be difficult to enforce certain business rules (for example, never allow deleted records to be updated) - -### Option 2: Use middleware to determine the behavior of read/update queries for deleted records - -Option two uses Prisma Client middleware to prevent soft deleted records from being returned. The following table describes how the middleware affects each query: - -| **Query** | **Middleware logic** | **Changes to return type** | -| :------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------- | -| `findUnique()` | 🔧 Change query to `findFirst` (because you cannot apply `deleted: false` filters to `findUnique()`)
🔧 Add `where: { deleted: false }` filter to exclude soft deleted posts
🔧 From version 5.0.0, you can use `findUnique()` to apply `delete: false` filters since [non unique fields are exposed](/orm/reference/prisma-client-reference#filter-on-non-unique-fields-with-userwhereuniqueinput). | No change | | -| `findMany` | 🔧 Add `where: { deleted: false }` filter to exclude soft deleted posts by default
🔧 Allow developers to **explicitly request** soft deleted posts by specifying `deleted: true` | No change | -| `update` | 🔧 Change query to `updateMany` (because you cannot apply `deleted: false` filters to `update`)
🔧 Add `where: { deleted: false }` filter to exclude soft deleted posts | `{ count: n }` instead of `Post` | -| `updateMany` | 🔧 Add `where: { deleted: false }` filter to exclude soft deleted posts | No change | - -- **Is it not possible to utilize soft delete with `findFirstOrThrow()` or `findUniqueOrThrow()`?**
- From version [5.1.0](https://github.com/prisma/prisma/releases/5.1.0), you can apply soft delete `findFirstOrThrow()` or `findUniqueOrThrow()` by using middleware. -- **Why are you making it possible to use `findMany()` with a `{ where: { deleted: true } }` filter, but not `updateMany()`?**
- This particular sample was written to support the scenario where a user can _restore_ their deleted blog post (which requires a list of soft deleted posts) - but the user should not be able to edit a deleted post. -- **Can I still `connect` or `connectOrCreate` a deleted post?**
- In this sample - yes. The middleware does not prevent you from connecting an existing, soft deleted post to a user. - -Run the following sample to see how middleware affects each query: - -```ts -import { PrismaClient, Prisma } from '@prisma/client' - -const prisma = new PrismaClient({}) - -async function main() { - /***********************************/ - /* SOFT DELETE MIDDLEWARE */ - /***********************************/ - - prisma.$use(async (params, next) => { - if (params.model == 'Post') { - if (params.action === 'findUnique' || params.action === 'findFirst') { - // Change to findFirst - you cannot filter - // by anything except ID / unique with findUnique() - params.action = 'findFirst' - // Add 'deleted' filter - // ID filter maintained - params.args.where['deleted'] = false - } - if ( - params.action === 'findFirstOrThrow' || - params.action === 'findUniqueOrThrow' - ) { - if (params.args.where) { - if (params.args.where.deleted == undefined) { - // Exclude deleted records if they have not been explicitly requested - params.args.where['deleted'] = false - } - } else { - params.args['where'] = { deleted: false } - } - } - if (params.action === 'findMany') { - // Find many queries - if (params.args.where) { - if (params.args.where.deleted == undefined) { - params.args.where['deleted'] = false - } - } else { - params.args['where'] = { deleted: false } - } - } - } - return next(params) - }) - - prisma.$use(async (params, next) => { - if (params.model == 'Post') { - if (params.action == 'update') { - // Change to updateMany - you cannot filter - // by anything except ID / unique with findUnique() - params.action = 'updateMany' - // Add 'deleted' filter - // ID filter maintained - params.args.where['deleted'] = false - } - if (params.action == 'updateMany') { - if (params.args.where != undefined) { - params.args.where['deleted'] = false - } else { - params.args['where'] = { deleted: false } - } - } - } - return next(params) - }) - - prisma.$use(async (params, next) => { - // Check incoming query type - if (params.model == 'Post') { - if (params.action == 'delete') { - // Delete queries - // Change action to an update - params.action = 'update' - params.args['data'] = { deleted: true } - } - if (params.action == 'deleteMany') { - // Delete many queries - params.action = 'updateMany' - if (params.args.data != undefined) { - params.args.data['deleted'] = true - } else { - params.args['data'] = { deleted: true } - } - } - } - return next(params) - }) - - /***********************************/ - /* TEST */ - /***********************************/ - - const titles = [ - { title: 'How to create soft delete middleware' }, - { title: 'How to install Prisma' }, - { title: 'How to update a record' }, - ] - - console.log('\u001b[1;34mSTARTING SOFT DELETE TEST \u001b[0m') - console.log('\u001b[1;34m#################################### \u001b[0m') - - let i = 0 - let posts = new Array() - - // Create 3 new posts with a randomly assigned title each time - for (i == 0; i < 3; i++) { - const createPostOperation = prisma.post.create({ - data: titles[Math.floor(Math.random() * titles.length)], - }) - posts.push(createPostOperation) - } - - var postsCreated = await prisma.$transaction(posts) - - console.log( - 'Posts created with IDs: ' + - '\u001b[1;32m' + - postsCreated.map((x) => x.id) + - '\u001b[0m' - ) - - // Delete the first post from the array - const deletePost = await prisma.post.delete({ - where: { - id: postsCreated[0].id, // Random ID - }, - }) - - // Delete the 2nd two posts - const deleteManyPosts = await prisma.post.deleteMany({ - where: { - id: { - in: [postsCreated[1].id, postsCreated[2].id], - }, - }, - }) - - const getOnePost = await prisma.post.findUnique({ - where: { - id: postsCreated[0].id, - }, - }) - - const getOneUniquePostOrThrow = async () => - await prisma.post.findUniqueOrThrow({ - where: { - id: postsCreated[0].id, - }, - }) - - const getOneFirstPostOrThrow = async () => - await prisma.post.findFirstOrThrow({ - where: { - id: postsCreated[0].id, - }, - }) - - const getPosts = await prisma.post.findMany({ - where: { - id: { - in: postsCreated.map((x) => x.id), - }, - }, - }) - - const getPostsAnDeletedPosts = await prisma.post.findMany({ - where: { - id: { - in: postsCreated.map((x) => x.id), - }, - deleted: true, - }, - }) - - const updatePost = await prisma.post.update({ - where: { - id: postsCreated[1].id, - }, - data: { - title: 'This is an updated title (update)', - }, - }) - - const updateManyDeletedPosts = await prisma.post.updateMany({ - where: { - deleted: true, - id: { - in: postsCreated.map((x) => x.id), - }, - }, - data: { - title: 'This is an updated title (updateMany)', - }, - }) - - console.log() - - console.log( - 'Deleted post (delete) with ID: ' + - '\u001b[1;32m' + - deletePost.id + - '\u001b[0m' - ) - console.log( - 'Deleted posts (deleteMany) with IDs: ' + - '\u001b[1;32m' + - [postsCreated[1].id + ',' + postsCreated[2].id] + - '\u001b[0m' - ) - console.log() - console.log( - 'findUnique: ' + - (getOnePost?.id != undefined - ? '\u001b[1;32m' + 'Posts returned!' + '\u001b[0m' - : '\u001b[1;31m' + - 'Post not returned!' + - '(Value is: ' + - JSON.stringify(getOnePost) + - ')' + - '\u001b[0m') - ) - try { - console.log('findUniqueOrThrow: ') - await getOneUniquePostOrThrow() - } catch (error) { - if ( - error instanceof Prisma.PrismaClientKnownRequestError && - error.code == 'P2025' - ) - console.log( - '\u001b[1;31m' + - 'PrismaClientKnownRequestError is catched' + - '(Error name: ' + - error.name + - ')' + - '\u001b[0m' - ) - } - try { - console.log('findFirstOrThrow: ') - await getOneFirstPostOrThrow() - } catch (error) { - if ( - error instanceof Prisma.PrismaClientKnownRequestError && - error.code == 'P2025' - ) - console.log( - '\u001b[1;31m' + - 'PrismaClientKnownRequestError is catched' + - '(Error name: ' + - error.name + - ')' + - '\u001b[0m' - ) - } - console.log() - console.log( - 'findMany: ' + - (getPosts.length == 3 - ? '\u001b[1;32m' + 'Posts returned!' + '\u001b[0m' - : '\u001b[1;31m' + 'Posts not returned!' + '\u001b[0m') - ) - console.log( - 'findMany ( delete: true ): ' + - (getPostsAnDeletedPosts.length == 3 - ? '\u001b[1;32m' + 'Posts returned!' + '\u001b[0m' - : '\u001b[1;31m' + 'Posts not returned!' + '\u001b[0m') - ) - console.log() - console.log( - 'update: ' + - (updatePost.id != undefined - ? '\u001b[1;32m' + 'Post updated!' + '\u001b[0m' - : '\u001b[1;31m' + - 'Post not updated!' + - '(Value is: ' + - JSON.stringify(updatePost) + - ')' + - '\u001b[0m') - ) - console.log( - 'updateMany ( delete: true ): ' + - (updateManyDeletedPosts.count == 3 - ? '\u001b[1;32m' + 'Posts updated!' + '\u001b[0m' - : '\u001b[1;31m' + 'Posts not updated!' + '\u001b[0m') - ) - console.log() - console.log('\u001b[1;34m#################################### \u001b[0m') - // 4. Count ALL posts - const f = await prisma.post.findMany({}) - console.log( - 'Number of active posts: ' + '\u001b[1;32m' + f.length + '\u001b[0m' - ) - - // 5. Count DELETED posts - const r = await prisma.post.findMany({ - where: { - deleted: true, - }, - }) - console.log( - 'Number of SOFT deleted posts: ' + '\u001b[1;32m' + r.length + '\u001b[0m' - ) -} - -main() -``` - -The sample outputs the following: - -``` -STARTING SOFT DELETE TEST -#################################### -Posts created with IDs: 680,681,682 - -Deleted post (delete) with ID: 680 -Deleted posts (deleteMany) with IDs: 681,682 - -findUnique: Post not returned!(Value is: []) -findMany: Posts not returned! -findMany ( delete: true ): Posts returned! - -update: Post not updated!(Value is: {"count":0}) -updateMany ( delete: true ): Posts not updated! - -#################################### -Number of active posts: 0 -Number of SOFT deleted posts: 95 -``` - -✔ Pros of this approach: - -- A developer can make a conscious choice to include deleted records in `findMany` -- You cannot accidentally read or update a deleted record - -✖ Cons of this approach: - -- Not obvious from API that you aren't getting all records and that `{ where: { deleted: false } }` is part of the default query -- Return type `update` affected because middleware changes the query to `updateMany` -- Doesn't handle complex queries with `AND`, `OR`, `every`, etc... -- Doesn't handle filtering when using `include` from another model. - -## FAQ - -### Can I add a global `includeDeleted` to the `Post` model? - -You may be tempted to 'hack' your API by adding a `includeDeleted` property to the `Post` model and make the following query possible: - -```ts -prisma.post.findMany({ where: { includeDeleted: true } }) -``` - -> **Note**: You would still need to write middleware. - -We **✘ do not** recommend this approach as it pollutes the schema with fields that do not represent real data. diff --git a/content/200-orm/200-prisma-client/300-client-extensions/500-middleware/200-logging-middleware.mdx b/content/200-orm/200-prisma-client/300-client-extensions/500-middleware/200-logging-middleware.mdx deleted file mode 100644 index b13eda09f9..0000000000 --- a/content/200-orm/200-prisma-client/300-client-extensions/500-middleware/200-logging-middleware.mdx +++ /dev/null @@ -1,90 +0,0 @@ ---- -title: 'Middleware sample: logging' -metaTitle: 'Middleware sample: logging (Reference)' -metaDescription: 'How to use middleware to log the time taken to perform any query.' ---- - - - -The following example logs the time taken for a Prisma Client query to run: - -```ts -const prisma = new PrismaClient() - -prisma.$use(async (params, next) => { - const before = Date.now() - - const result = await next(params) - - const after = Date.now() - - console.log(`Query ${params.model}.${params.action} took ${after - before}ms`) - - return result -}) - -const create = await prisma.post.create({ - data: { - title: 'Welcome to Prisma Day 2020', - }, -}) - -const createAgain = await prisma.post.create({ - data: { - title: 'All about database collation', - }, -}) -``` - -Example output: - -```no-lines -Query Post.create took 92ms -Query Post.create took 15ms -``` - -The example is based on the following sample schema: - -```prisma -generator client { - provider = "prisma-client-js" -} - -datasource db { - provider = "mysql" - url = env("DATABASE_URL") -} - -model Post { - authorId Int? - content String? - id Int @id @default(autoincrement()) - published Boolean @default(false) - title String - user User? @relation(fields: [authorId], references: [id]) - language String? - - @@index([authorId], name: "authorId") -} - -model User { - email String @unique - id Int @id @default(autoincrement()) - name String? - posts Post[] - extendedProfile Json? - role Role @default(USER) -} - -enum Role { - ADMIN - USER - MODERATOR -} -``` - - - -## Going further - -You can also use [Prisma Client extensions](/orm/prisma-client/client-extensions) to log the time it takes to perform a query. A functional example can be found in [this GitHub repository](https://github.com/prisma/prisma-client-extensions/tree/main/query-logging). diff --git a/content/200-orm/200-prisma-client/300-client-extensions/500-middleware/300-session-data-middleware.mdx b/content/200-orm/200-prisma-client/300-client-extensions/500-middleware/300-session-data-middleware.mdx deleted file mode 100644 index 6893713396..0000000000 --- a/content/200-orm/200-prisma-client/300-client-extensions/500-middleware/300-session-data-middleware.mdx +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: 'Middleware sample: session data' -metaTitle: 'Middleware sample: session data (Reference)' -metaDescription: 'How to use middleware to set the value taken from session state.' -hide_table_of_contents: true ---- - - - -The following example sets the `language` field of each `Post` to the context language (taken, for example, from session state): - -```ts -const prisma = new PrismaClient() - -const contextLanguage = 'en-us' // Session state - -prisma.$use(async (params, next) => { - if (params.model == 'Post' && params.action == 'create') { - params.args.data.language = contextLanguage - } - - return next(params) -}) - -const create = await prisma.post.create({ - data: { - title: 'My post in English', - }, -}) -``` - -The example is based on the following sample schema: - -```prisma -generator client { - provider = "prisma-client-js" -} - -datasource db { - provider = "mysql" - url = env("DATABASE_URL") -} - -model Post { - authorId Int? - content String? - id Int @id @default(autoincrement()) - published Boolean @default(false) - title String - user User? @relation(fields: [authorId], references: [id]) - language String? - - @@index([authorId], name: "authorId") -} - -model User { - email String @unique - id Int @id @default(autoincrement()) - name String? - posts Post[] - extendedProfile Json? - role Role @default(USER) -} - -enum Role { - ADMIN - USER - MODERATOR -} -``` - - diff --git a/content/200-orm/200-prisma-client/300-client-extensions/500-middleware/index.mdx b/content/200-orm/200-prisma-client/300-client-extensions/500-middleware/index.mdx deleted file mode 100644 index 9ce688e592..0000000000 --- a/content/200-orm/200-prisma-client/300-client-extensions/500-middleware/index.mdx +++ /dev/null @@ -1,193 +0,0 @@ ---- -title: 'Middleware' -metaTitle: 'Middleware (Reference)' -metaDescription: 'Prisma Client middleware allows you to perform actions before or after any query on any model with the prisma.$use method.' ---- - - - - - -**Middleware has been removed in [v6.14.0](https://pris.ly/release/6.14.0)** and had been deprecated since [v4.16.0](https://github.com/prisma/prisma/releases/tag/4.16.0). - -We recommend using the [Prisma Client extensions `query` component type](/orm/prisma-client/client-extensions/query) as an alternative to middleware. Prisma Client extensions were first introduced into Preview in version 4.7.0 and made Generally Available in 4.16.0. - -Prisma Client extensions allow you to create independent Prisma Client instances and bind each client to a specific filter or user. For example, you could bind clients to specific users to provide user isolation. Prisma Client extensions also provide end-to-end type safety. - - - -Middlewares act as query-level lifecycle hooks, which allow you to perform an action before or after a query runs. Use the [`prisma.$use`](/orm/reference/prisma-client-reference#use) method to add middleware, as follows: - -```ts highlight=4-9,12-17;normal -const prisma = new PrismaClient() - -// Middleware 1 -//highlight-start -prisma.$use(async (params, next) => { - // Manipulate params here - const result = await next(params) - // See results here - return result -}) -//highlight-end - -// Middleware 2 -//highlight-start -prisma.$use(async (params, next) => { - // Manipulate params here - const result = await next(params) - // See results here - return result -}) -//highlight-end - -// Queries here -``` - - - -Do not invoke `next` multiple times within a middleware when using [batch transactions](/orm/prisma-client/queries/transactions#sequential-prisma-client-operations). This will cause you to break out of the transaction and lead to unexpected results. - - - -[`params`](/orm/reference/prisma-client-reference#params) represent parameters available in the middleware, such as the name of the query, and [`next`](/orm/reference/prisma-client-reference#next) represents [the next middleware in the stack _or_ the original Prisma Client query](#running-order-and-the-middleware-stack). - -Possible use cases for middleware include: - -- Setting or overwriting a field value - for example, [setting the context language of a blog post comment](/orm/prisma-client/client-extensions/middleware/session-data-middleware) -- Validating input data - for example, check user input for inappropriate language via an external service -- Intercept a `delete` query and change it to an `update` in order to perform a [soft delete](/orm/prisma-client/client-extensions/middleware/soft-delete-middleware) -- [Log the time taken to perform a query](/orm/prisma-client/client-extensions/middleware/logging-middleware) - -There are many more use cases for middleware - this list serves as inspiration for the types of problems that middleware is designed to address. - - - -## Samples - -The following sample scenarios show how to use middleware in practice: - - - -## Where to add middleware - -Add Prisma Client middleware **outside the context of the request handler**, otherwise each request adds a new _instance_ of the middleware to the stack. The following example demonstrates where to add Prisma Client middleware in the context of an Express app: - -```ts highlight=6-11;normal -import express from 'express' -import { PrismaClient } from '@prisma/client' - -const prisma = new PrismaClient() - -//highlight-start -prisma.$use(async (params, next) => { - // Manipulate params here - const result = await next(params) - // See results here - return result -}) -//highlight-end - -const app = express() -app.get('/feed', async (req, res) => { - // NO MIDDLEWARE HERE - const posts = await prisma.post.findMany({ - where: { published: true }, - include: { author: true }, - }) - res.json(posts) -}) -``` - -## Running order and the middleware stack - -If you have multiple middlewares, the running order for **each separate query** is: - -1. All logic **before** `await next(params)` in each middleware, in descending order -2. All logic **after** `await next(params)` in each middleware, in ascending order - -Depending on where you are in the stack, `await next(params)` either: - -- Runs the next middleware (in middlewares #1 and #2 in the example) _or_ -- Runs the original Prisma Client query (in middleware #3) - -```ts -const prisma = new PrismaClient() - -// Middleware 1 -prisma.$use(async (params, next) => { - console.log(params.args.data.title) - console.log('1') - const result = await next(params) - console.log('6') - return result -}) - -// Middleware 2 -prisma.$use(async (params, next) => { - console.log('2') - const result = await next(params) - console.log('5') - return result -}) - -// Middleware 3 -prisma.$use(async (params, next) => { - console.log('3') - const result = await next(params) - console.log('4') - return result -}) - -const create = await prisma.post.create({ - data: { - title: 'Welcome to Prisma Day 2020', - }, -}) - -const create2 = await prisma.post.create({ - data: { - title: 'How to Prisma!', - }, -}) -``` - -Output: - -```no-lines -Welcome to Prisma Day 2020 -1 -2 -3 -4 -5 -6 -How to Prisma! -1 -2 -3 -4 -5 -6 -``` - -## Performance and appropriate use cases - -Middleware executes for **every** query, which means that overuse has the potential to negatively impact performance. To avoid adding performance overheads: - -- Check the `params.model` and `params.action` properties early in your middleware to avoid running logic unnecessarily: - - ```ts - prisma.$use(async (params, next) => { - if (params.model == 'Post' && params.action == 'delete') { - // Logic only runs for delete action and Post model - } - return next(params) - }) - ``` - -- Consider whether middleware is the appropriate solution for your scenario. For example: - - - If you need to populate a field, can you use the [`@default`](/orm/reference/prisma-schema-reference#default) attribute? - - If you need to set the value of a `DateTime` field, can you use the `now()` function or the `@updatedAt` attribute? - - If you need to perform more complex validation, can you use a `CHECK` constraint in the database itself? diff --git a/content/200-orm/200-prisma-client/300-client-extensions/index.mdx b/content/200-orm/200-prisma-client/300-client-extensions/index.mdx index cfcf31b5e2..d0bb657074 100644 --- a/content/200-orm/200-prisma-client/300-client-extensions/index.mdx +++ b/content/200-orm/200-prisma-client/300-client-extensions/index.mdx @@ -230,32 +230,6 @@ The `Prisma.Result` type utility is used to infer the type of the extended `User ## Limitations -### Usage of `$on` and `$use` with extended clients - -`$on` and `$use` are not available in extended clients. If you would like to continue using these [client-level methods](/orm/reference/prisma-client-reference#client-methods) with an extended client, you will need to hook them up before extending the client. - -```ts -const prisma = new PrismaClient() - -prisma.$use(async (params, next) => { - console.log('This is middleware!') - return next(params) -}) - -const xPrisma = prisma.$extends({ - name: 'myExtension', - model: { - user: { - async signUp(email: string) { - await prisma.user.create({ data: { email } }) - }, - }, - }, -}) -``` - -To learn more, see our documentation on [`$on`](/orm/reference/prisma-client-reference#on) and [`$use`](/orm/reference/prisma-client-reference#use) - ### Usage of client-level methods in extended clients [Client-level methods](/orm/reference/prisma-client-reference#client-methods) do not necessarily exist on extended clients. For these clients you will need to first check for existence before using. diff --git a/content/200-orm/200-prisma-client/600-observability-and-logging/250-opentelemetry-tracing.mdx b/content/200-orm/200-prisma-client/600-observability-and-logging/250-opentelemetry-tracing.mdx index 87230c0b81..f1b866c7d3 100644 --- a/content/200-orm/200-prisma-client/600-observability-and-logging/250-opentelemetry-tracing.mdx +++ b/content/200-orm/200-prisma-client/600-observability-and-logging/250-opentelemetry-tracing.mdx @@ -181,9 +181,7 @@ const sdk = new NodeSDK({ serviceName: 'my-service-name', // Replace with your service name traceExporter, instrumentations: [ - new PrismaInstrumentation({ - middleware: true, // Enable middleware tracing if needed - }), + new PrismaInstrumentation(), ], }) @@ -285,20 +283,6 @@ export function otelSetup() { } ``` -### Trace Prisma Client middleware - -By default, tracing does not output spans for [Prisma Client middleware](/orm/prisma-client/client-extensions/middleware). To include your middleware in your traces, set `middleware` to `true` in your `registerInstrumentations` statement, as follows: - -```ts -registerInstrumentations({ - instrumentations: [new PrismaInstrumentation({ middleware: true })], -}) -``` - -This will add the following span type to your traces: - -- `prisma:client:middleware`: Represents how long the operation spent in your [middleware](/orm/prisma-client/client-extensions/middleware). - ### Trace interactive transactions When you perform an interactive transaction, you'll see the following spans in addition to the [standard spans](#trace-output): diff --git a/content/200-orm/500-reference/050-prisma-client-reference.mdx b/content/200-orm/500-reference/050-prisma-client-reference.mdx index a9fe8c5afd..cc31ef781c 100644 --- a/content/200-orm/500-reference/050-prisma-client-reference.mdx +++ b/content/200-orm/500-reference/050-prisma-client-reference.mdx @@ -5514,63 +5514,6 @@ The `$connect()` method establishes a physical connection to the database via Pr The `$on()` method allows you to subscribe to [logging events](#log) or the [exit hook](/orm/prisma-client/setup-and-configuration/databases-connections/connection-management#exit-hooks). -### `$use()` - - - -`$use` is not available in [extended clients](/orm/prisma-client/client-extensions). Please [either migrate to query extensions](/orm/prisma-client/client-extensions/query) or use the `$use` method prior to extending your client. - - - -The `$use()` method adds [middleware](/orm/prisma-client/client-extensions/middleware) : - -```ts -prisma.$use(async (params, next) => { - console.log('This is middleware!'); - // Modify or interrogate params here - - return next(params); -}); -``` - -#### `next` - -`next` represents the "next level" in the middleware stack, which could be the next middleware or the Prisma Query, depending on [where in the stack you are](/orm/prisma-client/client-extensions/middleware#running-order-and-the-middleware-stack). - -#### `params` - -`params` is an object with information to use in your middleware. - -| Parameter | Description | -| :----------------- | :--------------------------------------------------------------------------------------------- | -| `action` | The query type - for example, `create` or `findMany`. | -| `args` | Arguments that were passed into the query - for example, `where`, `data`, or `orderBy` | -| `dataPath` | Populated if you use the [fluent API](/orm/prisma-client/queries/relation-queries#fluent-api). | -| `model` | The model type - for example, `Post` or `User`. | -| `runInTransaction` | Returns `true` if the query ran in the context of a [transaction](#transaction). | - -:::tip - -If you need the `model` property as a string, use: `String(params.model)` - -::: - -Example parameter values: - -```js -{ - args: { where: { id: 15 } }, - dataPath: [ 'select', 'author', 'select', 'posts' ], - runInTransaction: false, - action: 'findMany', - model: 'Post' -} -``` - -#### Examples - -See [middleware examples](/orm/prisma-client/client-extensions/middleware#samples). - ### `$queryRawTyped` See: [Using Raw SQL (`$queryRawTyped`)](/orm/prisma-client/using-raw-sql/typedsql). diff --git a/content/200-orm/500-reference/500-preview-features/050-client-preview-features.mdx b/content/200-orm/500-reference/500-preview-features/050-client-preview-features.mdx index 469421c32c..1ea24923c5 100644 --- a/content/200-orm/500-reference/500-preview-features/050-client-preview-features.mdx +++ b/content/200-orm/500-reference/500-preview-features/050-client-preview-features.mdx @@ -12,16 +12,16 @@ For more information, see [ORM releases and maturity levels](/orm/more/releases) The following [Preview](/orm/more/releases#preview) feature flags are available for Prisma Client and Prisma schema: -| Feature | Released into Preview | Feedback issue | -| ------------------------------------------------------------------------------- | :------------------------------------------------------------- | :-------------------------------------------------------------------: | -| [`metrics`](/orm/prisma-client/observability-and-logging/metrics) | [3.15.0](https://github.com/prisma/prisma/releases/tag/3.15.0) | [Submit feedback](https://github.com/prisma/prisma/issues/13579) | -| [`views`](/orm/prisma-schema/data-model/views) | [4.9.0](https://github.com/prisma/prisma/releases/tag/4.9.0) | [Submit feedback](https://github.com/prisma/prisma/issues/17335) | -| `relationJoins` | [5.7.0](https://github.com/prisma/prisma/releases/tag/5.7.0) | [Submit feedback](https://github.com/prisma/prisma/discussions/22288) | -| `nativeDistinct` | [5.7.0](https://github.com/prisma/prisma/releases/tag/5.7.0) | [Submit feedback](https://github.com/prisma/prisma/discussions/22287) | -| `typedSql` | [5.19.0](https://github.com/prisma/prisma/releases/tag/5.19.0) | [Submit feedback](https://github.com/prisma/prisma/discussions/25106) | -| `strictUndefinedChecks` | [5.20.0](https://github.com/prisma/prisma/releases/tag/5.20.0) | [Submit feedback](https://github.com/prisma/prisma/discussions/25271) | -| [`fullTextSearchPostgres`](/orm/prisma-client/queries/full-text-search) | [6.0.0](https://github.com/prisma/prisma/releases/tag/6.0.0) | [Submit feedback](https://github.com/prisma/prisma/issues/25773) | -| `shardKeys` | [6.10.0](https://pris.ly/release/6.10.0) | [Submit feedback](https://github.com/prisma/prisma/issues/) | +| Feature | Released into Preview | Feedback issue | +| ----------------------------------------------------------------------- | :------------------------------------------------------------- | :-------------------------------------------------------------------: | +| [`metrics`](/orm/prisma-client/observability-and-logging/metrics) | [3.15.0](https://github.com/prisma/prisma/releases/tag/3.15.0) | [Submit feedback](https://github.com/prisma/prisma/issues/13579) | +| [`views`](/orm/prisma-schema/data-model/views) | [4.9.0](https://github.com/prisma/prisma/releases/tag/4.9.0) | [Submit feedback](https://github.com/prisma/prisma/issues/17335) | +| `relationJoins` | [5.7.0](https://github.com/prisma/prisma/releases/tag/5.7.0) | [Submit feedback](https://github.com/prisma/prisma/discussions/22288) | +| `nativeDistinct` | [5.7.0](https://github.com/prisma/prisma/releases/tag/5.7.0) | [Submit feedback](https://github.com/prisma/prisma/discussions/22287) | +| `typedSql` | [5.19.0](https://github.com/prisma/prisma/releases/tag/5.19.0) | [Submit feedback](https://github.com/prisma/prisma/discussions/25106) | +| `strictUndefinedChecks` | [5.20.0](https://github.com/prisma/prisma/releases/tag/5.20.0) | [Submit feedback](https://github.com/prisma/prisma/discussions/25271) | +| [`fullTextSearchPostgres`](/orm/prisma-client/queries/full-text-search) | [6.0.0](https://github.com/prisma/prisma/releases/tag/6.0.0) | [Submit feedback](https://github.com/prisma/prisma/issues/25773) | +| `shardKeys` | [6.10.0](https://pris.ly/release/6.10.0) | [Submit feedback](https://github.com/prisma/prisma/issues/) | To enable a Preview feature, [add the feature flag to the `generator` block](#enabling-a-prisma-client-preview-feature) in your `schema.prisma` file. [Share your feedback on all Preview features on GitHub](https://github.com/prisma/prisma/issues/3108). @@ -86,6 +86,5 @@ In the list below, you can find a history of Prisma Client and Prisma schema fea | [`connectOrCreate`](/orm/reference/prisma-client-reference#connectorcreate) | [2.1.0](https://github.com/prisma/prisma/releases/tag/2.1.0) | [2.11.0](https://github.com/prisma/prisma/releases/tag/2.11.0) | | [`atomicNumberOperations`](/orm/reference/prisma-client-reference#atomic-number-operations) | [2.6.0](https://github.com/prisma/prisma/releases/tag/2.6.0) | [2.10.0](https://github.com/prisma/prisma/releases/tag/2.10.0) | | [`insensitiveFilters` (PostgreSQL)](/orm/prisma-client/queries/filtering-and-sorting#case-insensitive-filtering) | [2.5.0](https://github.com/prisma/prisma/releases/tag/2.5.0) | [2.8.0](https://github.com/prisma/prisma/releases/tag/2.8.0) | -| [`middlewares`](/orm/prisma-client/client-extensions/middleware) | [2.3.0](https://github.com/prisma/prisma/releases/tag/2.3.0) | [2.5.0](https://github.com/prisma/prisma/releases/tag/2.5.0) | | [`aggregateApi`](/orm/prisma-client/queries/aggregation-grouping-summarizing#aggregate) | [2.2.0](https://github.com/prisma/prisma/releases/tag/2.2.0) | [2.5.0](https://github.com/prisma/prisma/releases/tag/2.5.0) | | [`distinct`](/orm/reference/prisma-client-reference#distinct) | [2.3.0](https://github.com/prisma/prisma/releases/tag/2.3.0) | [2.5.0](https://github.com/prisma/prisma/releases/tag/2.5.0) | diff --git a/content/200-orm/800-more/350-ai-tools/100-cursor.mdx b/content/200-orm/800-more/350-ai-tools/100-cursor.mdx index 9d8275a356..2ab60d89ab 100644 --- a/content/200-orm/800-more/350-ai-tools/100-cursor.mdx +++ b/content/200-orm/800-more/350-ai-tools/100-cursor.mdx @@ -105,10 +105,6 @@ Schema Design Prisma Client Usage - Always use type-safe Prisma client operations. - Prefer transactions for complex, multi-step operations. -- Use Prisma middleware for cross-cutting concerns: - - Logging - - Soft delete - - Auditing - Handle optional relations explicitly. - Use Prisma's filtering and pagination capabilities. Database Migrations diff --git a/content/200-orm/800-more/350-ai-tools/300-windsurf.mdx b/content/200-orm/800-more/350-ai-tools/300-windsurf.mdx index b312ff8758..814c77f782 100644 --- a/content/200-orm/800-more/350-ai-tools/300-windsurf.mdx +++ b/content/200-orm/800-more/350-ai-tools/300-windsurf.mdx @@ -110,10 +110,6 @@ Schema Design Prisma Client Usage - Always use type-safe Prisma client operations. - Prefer transactions for complex, multi-step operations. -- Use Prisma middleware for cross-cutting concerns: - - Logging - - Soft delete - - Auditing - Handle optional relations explicitly. - Use Prisma's filtering and pagination capabilities. Database Migrations diff --git a/content/200-orm/800-more/350-ai-tools/400-github-copilot.mdx b/content/200-orm/800-more/350-ai-tools/400-github-copilot.mdx index b36b38026d..740f3b9305 100644 --- a/content/200-orm/800-more/350-ai-tools/400-github-copilot.mdx +++ b/content/200-orm/800-more/350-ai-tools/400-github-copilot.mdx @@ -206,7 +206,6 @@ You can tailor Copilot Chat's behavior in your repository by [adding a `.github/ new PrismaClient({ log: ['query', 'warn', 'error'] }); /``` * **APM integration** (Datadog, Sentry) – capture latency, errors. -* **Client extensions** for metrics: create extensions that wrap calls to emit timing and telemetry instead of middleware. ### 11. Security & Best Practices diff --git a/content/250-postgres/400-query-optimization/100-setup.mdx b/content/250-postgres/400-query-optimization/100-setup.mdx index c5d87ea33d..c4737247b1 100644 --- a/content/250-postgres/400-query-optimization/100-setup.mdx +++ b/content/250-postgres/400-query-optimization/100-setup.mdx @@ -75,18 +75,14 @@ const prisma = new PrismaClient().$extends( ).$extends(withAccelerate()); ``` -#### Using the Optimize extension with other extensions or middleware +#### Using the Optimize extension with other extensions Since [extensions are applied one after another](/orm/prisma-client/client-extensions#conflicts-in-combined-extensions), make sure you apply them in the correct order. Extensions cannot share behavior and the last extension applied takes precedence. ```ts -const prisma = new PrismaClient().$extends(withOptimize()).$extends(withAccelerate()) -``` - -If you are using [Prisma Middleware](/orm/prisma-client/client-extensions/middleware) in your application, make sure they are added before any Prisma Client extensions (like Optimize). For example: - -```ts -const prisma = new PrismaClient().$use(middleware).$extends(withOptimize()).$extends(withAccelerate()) +const prisma = new PrismaClient() + .$extends(withOptimize()) + .$extends(withAccelerate()) ``` ### 2.5. Use Prisma Optimize to generate insights diff --git a/content/300-accelerate/200-getting-started.mdx b/content/300-accelerate/200-getting-started.mdx index 3452f94539..b06abc67a4 100644 --- a/content/300-accelerate/200-getting-started.mdx +++ b/content/300-accelerate/200-getting-started.mdx @@ -148,7 +148,7 @@ const prisma = new PrismaClient().$extends(withAccelerate()) If VS Code does not recognize the `$extends` method, refer to [this section](/accelerate/faq#vs-code-does-not-recognize-the-extends-method) on how to resolve the issue. -#### Using the Accelerate extension with other extensions or middleware +#### Using the Accelerate extension with other extensions Since [extensions are applied one after another](/orm/prisma-client/client-extensions#conflicts-in-combined-extensions), make sure you apply them in the correct order. Extensions cannot share behavior and the last extension applied takes precedence. @@ -158,12 +158,6 @@ If you are using [Prisma Optimize](/optimize) in your application, make sure you const prisma = new PrismaClient().$extends(withOptimize()).$extends(withAccelerate()) ``` -If you are using [Prisma Middleware](/orm/prisma-client/client-extensions/middleware) in your application, make sure they are added before any Prisma Client extensions (like Accelerate). For example: - -```ts -const prisma = new PrismaClient().$use(middleware).$extends(withAccelerate()) -``` - ### 2.5. Use Accelerate in your database queries The `withAccelerate` extension primarily does two things: diff --git a/content/700-optimize/200-getting-started.mdx b/content/700-optimize/200-getting-started.mdx index d3e4fa9078..cb67d6a86d 100644 --- a/content/700-optimize/200-getting-started.mdx +++ b/content/700-optimize/200-getting-started.mdx @@ -70,7 +70,7 @@ const prisma = new PrismaClient().$extends( ); ``` -#### Using the Optimize extension with other extensions or middleware +#### Using the Optimize extension with other extensions Since [extensions are applied one after another](/orm/prisma-client/client-extensions#conflicts-in-combined-extensions), make sure you apply them in the correct order. Extensions cannot share behavior and the last extension applied takes precedence. @@ -80,12 +80,6 @@ If you are using [Prisma Accelerate](/accelerate) in your application, make sure const prisma = new PrismaClient().$extends(withOptimize()).$extends(withAccelerate()) ``` -If you are using [Prisma Middleware](/orm/prisma-client/client-extensions/middleware) in your application, make sure they are added before any Prisma Client extensions (like Optimize). For example: - -```ts -const prisma = new PrismaClient().$use(middleware).$extends(withOptimize()) -``` - ### 2.5. Use Prisma Optimize to generate insights Follow these steps to start generating query insights with Prisma Optimize: From f3bb75bbd59cbc9994c75d582717ed8ac415c5d2 Mon Sep 17 00:00:00 2001 From: Mike Hartington Date: Sat, 15 Nov 2025 20:08:01 -0500 Subject: [PATCH 6/9] docs(tanstack): update guides for v7 --- content/800-guides/160-tanstack-start.mdx | 604 ++++------------------ 1 file changed, 92 insertions(+), 512 deletions(-) diff --git a/content/800-guides/160-tanstack-start.mdx b/content/800-guides/160-tanstack-start.mdx index 971908e4d4..296559acf5 100644 --- a/content/800-guides/160-tanstack-start.mdx +++ b/content/800-guides/160-tanstack-start.mdx @@ -21,327 +21,44 @@ This guide will walk you through integrating Prisma ORM with a Prisma Postgres d To begin, create a new TanStack Start project. -:::note - -For the purpose of this guide, we're using the same setup instructions that you can find in the [TanStart Start docs](https://tanstack.com/start/latest/docs/framework/react/build-from-scratch). - -::: - -In the directory where you'd like to create your project, run the following commands: - ```terminal -mkdir tanstack-start-prisma -cd tanstack-start-prisma -npm init -y -``` - -This will create a new folder called `tanstack-start-prisma`, navigate into it, and initialize a new Node.js project. - -Open the directory in your IDE and create a `tsconfig.json` file with the following configuration: - -```json file=tsconfig.json -{ - "compilerOptions": { - "jsx": "react-jsx", - "moduleResolution": "Bundler", - "module": "ESNext", - "target": "ES2022", - "skipLibCheck": true, - "strictNullChecks": true - } -} +npm create @tanstack/start@latest ``` -We also need a `.gitignore` file, so let's set that up now: - -```txt file=.gitignore -node_modules -.env -app/generated -``` - -Next, install TanStack Router and Vinxi, as TanStack Start currently requires them: - -```terminal -npm install @tanstack/react-start @tanstack/react-router vinxi -``` - -We also need React, the Vite React plugin, and TypeScript: - -```terminal -npm install react react-dom -npm install --save-dev @vitejs/plugin-react vite-tsconfig-paths -npm install --save-dev typescript @types/react @types/react-dom -``` - -Update your `package.json` to use Vinxi's CLI. Add `"type": "module"` and modify the scripts to use Vinxi's CLI: - -```json file=package.json -{ - "name": "tanstack-start-prisma", - "version": "1.0.0", - "main": "index.js", - // add-start - "type": "module", - "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" - }, - // add-end - "keywords": [], - "author": "", - "license": "ISC", - "description": "", - "dependencies": { - "@tanstack/react-router": "^1.119.0", - "@tanstack/react-start": "^1.119.0", - "react": "^19.1.0", - "react-dom": "^19.1.0", - "vinxi": "^0.5.6" - }, - "devDependencies": { - "@types/react": "^19.1.2", - "@types/react-dom": "^19.1.3", - "@vitejs/plugin-react": "^4.4.1", - "typescript": "^5.8.3", - "vite-tsconfig-paths": "^5.1.4" - } -} -``` - -Then, create and configure TanStack Start's `app.config.ts` file: - -```typescript file=app.config.ts -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) -``` - -For TanStack Start to function, we need 5 files in `~/app/`: - -- `router.tsx` (The router configuration) -- `ssr.tsx` (The server entry point) -- `client.tsx` (The client entry point) -- `routes/__root.tsx` (The root of the app) -- `routes/index.tsx` (The home page) - -You can create them with these commands: - -```terminal -mkdir app -touch app/router.tsx -touch app/ssr.tsx -touch app/client.tsx -mkdir app/routes -touch app/routes/__root.tsx -touch app/routes/index.tsx -``` - -`router.tsx` configures the application's main router with route definitions and settings: - -```typescript file=app/router.tsx -import { createRouter as createTanStackRouter } from '@tanstack/react-router' -import { routeTree } from './routeTree.gen' - -export function createRouter() { - const router = createTanStackRouter({ - routeTree, - scrollRestoration: true, - }) - - return router -} - -declare module '@tanstack/react-router' { - interface Register { - router: ReturnType - } -} -``` - -:::note - -You should be seeing an error about `routeTree.gen.ts` not existing. This is expected. It will be generated when you run TanStack Start for the first time. - +:::info +- *What would you like to name your project?* tanstack-start-prisma +- *Would you like to use Tailwind CSS?* No +- *Selecte Toolchain* None +- *Select deployment adapter* Nitro +- *What add-ons would you like for your project?* Prisma +- *Would you like any examples?* No +- *Prisma: Database Provider* Prisma PostgresSQL ::: -`ssr.tsx` allows us to know what routes and loaders we need to execute when the user hits a given route: - -```typescript file=app/ssr.tsx -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) -``` - -`client.tsx` initializes the client-side logic to handle routes in the browser: - -```typescript file=app/client.tsx -import { hydrateRoot } from "react-dom/client"; -import { StartClient } from "@tanstack/react-start/client"; -import { createRouter } from "./router"; +This will create a new folder called `tanstack-start-prisma` and create a new Prisma Postgres +Database for you. The final database connection string will be printed out. -const router = createRouter(); - -hydrateRoot(document, ); +```shell +● Database Connection +│ +│ Connection String: +│ +│ postgresql://b4889..... +│ ``` -`routes/__root.tsx` defines the root route and global HTML layout for the entire application: - -```typescript file=app/routes/__root.tsx -import type { ReactNode } from "react"; -import { - Outlet, - createRootRoute, - HeadContent, - Scripts, -} from "@tanstack/react-router"; - -export const Route = createRootRoute({ - head: () => ({ - meta: [ - { - charSet: "utf-8", - }, - { - name: "viewport", - content: "width=device-width, initial-scale=1", - }, - { - title: "Prisma TanStack Start Demo", - }, - ], - }), - component: RootComponent, -}); - -function RootComponent() { - return ( - - - - ); -} +Copy this connection string and set the `DATABASE_URL` variable in `.env.local`: -function RootDocument({ children }: Readonly<{ children: ReactNode }>) { - return ( - - - - - - {children} - - - - ); -} +``` +# Database URL for PostgreSQL +DATABASE_URL="postgresql://b4889....." ``` -`routes/index.tsx` is the home page of the application: +## 2. Configure Prisma -```typescript file=app/routes/index.tsx -import { createFileRoute } from "@tanstack/react-router"; +### 2.1. Define your Prisma Schema -export const Route = createFileRoute("/")({ - component: Home, -}); - -function Home() { - return ( -
-

Posts

-
- ); -} -``` - -Now, run: - -```terminal -npm run dev -``` - -This will generate the `routeTree.gen.ts` file and resolve any routing errors. - -Your file tree should look like this (without `node_modules`): - -``` -. -├── app -│ ├── client.tsx -│ ├── routeTree.gen.ts -│ ├── router.tsx -│ ├── routes -│ │ ├── __root.tsx -│ │ └── index.tsx -│ └── ssr.tsx -├── app.config.ts -├── package-lock.json -├── package.json -└── tsconfig.json -``` - -## 2. Install and Configure Prisma - -### 2.1. Install dependencies - -To get started with Prisma, you'll need to install a few dependencies: - - - -```terminal -npm install prisma tsx --save-dev -npm install @prisma/extension-accelerate @prisma/client dotenv -``` - - -```terminal -npm install prisma tsx --save-dev -npm install @prisma/client dotenv -``` - - - -Once installed, initialize Prisma in your project: - -```terminal -npx prisma init --db --output ../app/generated/prisma -``` - -:::info -You'll need to answer a few questions while setting up your Prisma Postgres database. Select the region closest to your location and a memorable name for your database like "My __________ Project" -::: - -This will create: - -- A `prisma` directory with a `schema.prisma` file. -- A `prisma.config.ts` file for configuring Prisma -- A Prisma Postgres database. -- A `.env` file containing the `DATABASE_URL` at the project root. -- An `output` directory for the generated Prisma Client as `app/generated/prisma`. - -### 2.2. Define your Prisma Schema - -In `schema.prisma`, create a model for our posts and change the generator to use the [`prisma-client`](/orm/prisma-schema/overview/generators#prisma-client) provider: +In `schema.prisma`, the model for our todos is defined below the generator and datasource blocks: ```prisma file=prisma/schema.prisma generator client { @@ -351,209 +68,96 @@ generator client { datasource db { provider = "postgresql" - url = env("DATABASE_URL") -} - -//add-start -model User { - id Int @id @default(autoincrement()) - email String @unique - name String? - posts Post[] } -model Post { - id Int @id @default(autoincrement()) +model Todo { + id Int @id @default(autoincrement()) title String - content String? - published Boolean @default(false) - authorId Int - author User @relation(fields: [authorId], references: [id]) + createdAt DateTime @default(now()) } -//add-end ``` -This creates two models: `User` and `Post`, with a one-to-many relationship between them. +This creates a `Todod` model that will be pushed to the database -### 2.3 Add `dotenv` to `prisma.config.ts` +### 2.2. Configure the Prisma Client generator -To get access to the variables in the `.env` file, they can either be loaded by your runtime, or by using `dotenv`. -Include an import for `dotenv` at the top of the `prisma.config.ts` - -```ts -//add-start -import 'dotenv/config' -//add-end -import { defineConfig, env } from 'prisma/config'; -export default defineConfig({ - schema: 'prisma/schema.prisma', - migrations: { - path: 'prisma/migrations', - }, - engine: 'classic', - datasource: { - url: env('DATABASE_URL'), - }, -}); -``` - -### 2.4. Configure the Prisma Client generator - -Now, run the following command to create the database tables and generate the Prisma Client: +Now, run the following command to create the database tables: ```terminal -npx prisma migrate dev --name init +npm run db:seed -- --name init ``` ### 2.5. Seed the database -Let's add some seed data to populate the database with sample users and posts. - -Create a new file called `seed.ts` in the `prisma/` directory: - -```typescript file=prisma/seed.ts -import { PrismaClient, Prisma } from "../app/generated/prisma/client.js"; - -const prisma = new PrismaClient(); - -const userData: Prisma.UserCreateInput[] = [ - { - name: "Alice", - email: "alice@prisma.io", - posts: { - create: [ - { - title: "Join the Prisma Discord", - content: "https://pris.ly/discord", - published: true, - }, - { - title: "Prisma on YouTube", - content: "https://pris.ly/youtube", - }, - ], - }, - }, - { - name: "Bob", - email: "bob@prisma.io", - posts: { - create: [ - { - title: "Follow Prisma on Twitter", - content: "https://www.twitter.com/prisma", - published: true, - }, - ], - }, - }, -]; -export async function main() { - for (const u of userData) { - await prisma.user.create({ data: u }); - } -} -main(); -``` +Generate the Prisma Client needed for the project; -Now, tell Prisma how to run this script by updating your `prisma.config.ts`: - -```ts file=prisma.config.ts -import 'dotenv/config' -import { defineConfig, env } from 'prisma/config'; -export default defineConfig({ - schema: 'prisma/schema.prisma', - migrations: { - path: 'prisma/migrations', -//add-start - seed: `tsx prisma/seed.ts`, -//add-end - }, - engine: 'classic', - datasource: { - url: env('DATABASE_URL'), - }, -}); +```terminal +npm run db:generate ``` -Run the seed script: +Then seed the project with the `seed.ts` file in the `prisma/` directory: ```terminal -npx prisma db seed +npm run db:seed ``` And open Prisma Studio to inspect your data: ```terminal -npx prisma studio +npm run db:studio ``` ## 3. Integrate Prisma into TanStack Start -### 3.1 Create a Prisma Client +### 3.1 The Prisma Client -Instead of creating a new Prisma Client instance in each file, create a single instance in a shared file to be used globally. +Instead of creating a new Prisma Client instance in each file, TanStack Start has a `db.ts` that +creates a single instance that can be shared globally -Create a `/lib` directory and a `prisma.ts` file inside it. This file will be used to create and export your Prisma Client instance. +```tsx file=src/db.ts +import { PrismaClient } from './generated/prisma/client.js' -Set up the Prisma client like this: +import { PrismaPg } from '@prisma/adapter-pg' - - -```tsx file=src/lib/prisma.ts -import { PrismaClient } from "../generated/prisma/client.js"; -import { withAccelerate } from "@prisma/extension-accelerate"; - -const prisma = new PrismaClient().$extends(withAccelerate()); +const adapter = new PrismaPg({ + connectionString: process.env.DATABASE_URL!, +}) -export default prisma; -``` - - -```tsx file=src/lib/prisma.ts -import { PrismaClient } from "../generated/prisma/client.js"; +declare global { + var __prisma: PrismaClient | undefined +} -const prisma = new PrismaClient(); +export const prisma = globalThis.__prisma || new PrismaClient({ adapter }) -export default prisma; +if (process.env.NODE_ENV !== 'production') { + globalThis.__prisma = prisma +} ``` - - -:::warning -We recommend using a connection pooler (like [Prisma Accelerate](https://www.prisma.io/accelerate)) to manage database connections efficiently. - -If you choose not to use one, **avoid** instantiating `PrismaClient` globally in long-lived environments. Instead, create and dispose of the client per request to prevent exhausting your database connections. -::: -### 3.2 Fetch users and posts on load +### 3.2 Fetch data on load -First, import the necessary modules. Then, create a server function using the [`createServerFn`](https://tanstack.com/start/latest/docs/framework/react/guide/server-functions) function. This function will fetch the users from the database using the `.findMany()` method. Use the [`include`](/orm/prisma-client/queries/relation-queries#include-a-relation) option to fetch the related posts: +First, import the necessary modules. Then, create a server function using the [`createServerFn`](https://tanstack.com/start/latest/docs/framework/react/guide/server-functions) function. This function will fetch the data from the database using the `.findMany()` method -```typescript file=app/routes/index.tsx +```typescript file=src/routes/index.tsx +import { createFileRoute } from "@tanstack/react-router"; // add-start -import { prisma } from "../lib/prisma"; import { createServerFn } from "@tanstack/react-start"; +import { prisma } from '../db'; // add-end -import { createFileRoute } from "@tanstack/react-router"; export const Route = createFileRoute("/")({ component: Home, }); // add-start -const getUsers = createServerFn({ method: "GET" }).handler(async () => { - return prisma.user.findMany({ - include: { - posts: true, - }, - }); +const getTodos = createServerFn({ method: "GET" }).handler(async () => { + return prisma.todo.findMany(); }); // add-end function Home() { return (
-

Posts

); } @@ -562,31 +166,27 @@ function Home() { TanStack Start allows functions to run on load with loader functions in the [`createFileRoute`](https://tanstack.com/router/latest/docs/framework/react/api/router/createFileRouteFunction) function. Fetch the users and their posts on load with this code: ```typescript file=app/routes/index.tsx -import { prisma } from "../lib/prisma"; -import { createServerFn } from "@tanstack/react-start"; -import { createFileRoute } from "@tanstack/react-router"; +import { createFileRoute } from '@tanstack/react-router'; +import { createServerFn } from '@tanstack/react-start'; +import { prisma } from '../db'; export const Route = createFileRoute("/")({ component: Home, // add-start loader: () => { - return getUsers(); + return getTodos(); }, // add-end }); -const getUsers = createServerFn({ method: "GET" }).handler(async () => { - return prisma.user.findMany({ - include: { - posts: true, - }, - }); +const getTodos = createServerFn({ method: "GET" }).handler(async () => { + return prisma.todo.findMany(); }); function Home() { return (
-

Posts

+

Todos

); } @@ -595,90 +195,70 @@ function Home() { Store the response from the loader in the main component using [`Route.useLoaderData()`](https://tanstack.com/router/latest/docs/framework/react/api/router/useLoaderDataHook): ```typescript file=app/routes/index.tsx -import { prisma } from "../lib/prisma"; import { createServerFn } from "@tanstack/react-start"; import { createFileRoute } from "@tanstack/react-router"; +import { prisma } from '../db'; export const Route = createFileRoute("/")({ component: Home, loader: () => { - return getUsers(); + return getTodos(); }, }); -const getUsers = createServerFn({ method: "GET" }).handler(async () => { - return prisma.user.findMany({ - include: { - posts: true, - }, - }); +const getTodos = createServerFn({ method: "GET" }).handler(async () => { + return prisma.todo.findMany(); }); function Home() { // add-start - const users = Route.useLoaderData(); + const todos = Route.useLoaderData(); // add-end return (
-

Posts

+

Todos

); } ``` -### 3.3 Display the users and posts +### 3.3 Display the todos -Next, you'll update the home page to display the users and posts retrieved from your database. +Next, you'll update the home page to display the data retrieved from your database. -Map over the `users` and display them in a list along with their `posts`: +Map over the `todos` and display them in a list: ```typescript file=app/routes/index.tsx -import { createFileRoute } from "@tanstack/react-router"; -import { createServerFn } from "@tanstack/react-start"; -import prisma from "../../lib/prisma"; +import { createFileRoute } from '@tanstack/react-router'; +import { createServerFn } from '@tanstack/react-start'; +import { prisma } from '../db'; -export const Route = createFileRoute("/")({ - component: Home, - loader: () => { - return getUsers(); - }, +export const Route = createFileRoute('/')({ + component: App, + loader: () => getTodos(), }); -const getUsers = createServerFn({ method: "GET" }).handler(async () => { - return prisma.user.findMany({ - include: { - posts: true, - }, - }); +const getTodos = createServerFn({ method: 'GET' }).handler(async () => { + return prisma.todo.findMany(); }); -function Home() { - const users = Route.useLoaderData(); - +function App() { + const todos = Route.useLoaderData(); + return (
-

Posts

- // add-start
    - {users.map((user) => ( -
  • - {user.name} -
      - {user.posts.map((post) => ( -
    • {post.title}
    • - ))} -
    -
  • + {todos.map(todo => ( +
  • {todo.title}
  • ))}
- // add-end
); } ``` -This setup will display the posts on your page, fetched directly from your database. +This setup will display the todos on your page, fetched directly from your database. ## Next steps @@ -692,4 +272,4 @@ You've successfully integrated Prisma ORM with TanStack Start, creating a seamle ## More info - [Prisma ORM Documentation](/orm/overview/introduction) -- [TanStack Start Documentation](https://tanstack.com/start/latest/docs/framework/react/overview) +- [TanStack Start Documentation](https://tanstack.com/start/latest/docs/framework/react/overview) \ No newline at end of file From 254f45c78ade74a3ce6c82d5ba0ce0cc039a49f9 Mon Sep 17 00:00:00 2001 From: Mike Hartington Date: Mon, 17 Nov 2025 20:13:37 -0500 Subject: [PATCH 7/9] Update content/800-guides/160-tanstack-start.mdx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- content/800-guides/160-tanstack-start.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/800-guides/160-tanstack-start.mdx b/content/800-guides/160-tanstack-start.mdx index 296559acf5..71cbe41cda 100644 --- a/content/800-guides/160-tanstack-start.mdx +++ b/content/800-guides/160-tanstack-start.mdx @@ -28,7 +28,7 @@ npm create @tanstack/start@latest :::info - *What would you like to name your project?* tanstack-start-prisma - *Would you like to use Tailwind CSS?* No -- *Selecte Toolchain* None +- *Select Toolchain* None - *Select deployment adapter* Nitro - *What add-ons would you like for your project?* Prisma - *Would you like any examples?* No From d9af468a91d878aac8cebd829d328bb05dfeb660 Mon Sep 17 00:00:00 2001 From: Mike Hartington Date: Mon, 17 Nov 2025 20:13:49 -0500 Subject: [PATCH 8/9] Update content/800-guides/160-tanstack-start.mdx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- content/800-guides/160-tanstack-start.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/800-guides/160-tanstack-start.mdx b/content/800-guides/160-tanstack-start.mdx index 71cbe41cda..460253a359 100644 --- a/content/800-guides/160-tanstack-start.mdx +++ b/content/800-guides/160-tanstack-start.mdx @@ -77,7 +77,7 @@ model Todo { } ``` -This creates a `Todod` model that will be pushed to the database +This creates a `Todo` model that will be pushed to the database ### 2.2. Configure the Prisma Client generator From e5848d407ebf1139a336ed9c0e6d118be2970f4e Mon Sep 17 00:00:00 2001 From: Mike Hartington Date: Mon, 17 Nov 2025 20:15:03 -0500 Subject: [PATCH 9/9] docs(): update based on feedback --- content/800-guides/160-tanstack-start.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/800-guides/160-tanstack-start.mdx b/content/800-guides/160-tanstack-start.mdx index 460253a359..17b53d986c 100644 --- a/content/800-guides/160-tanstack-start.mdx +++ b/content/800-guides/160-tanstack-start.mdx @@ -86,7 +86,7 @@ Now, run the following command to create the database tables: ```terminal npm run db:seed -- --name init ``` -### 2.5. Seed the database +### 2.3. Seed the database Generate the Prisma Client needed for the project;