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/6] 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/6] 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/6] 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/6] 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/6] 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 bfdbc1625794e2d46b77fb7f39f9f720d8ecc220 Mon Sep 17 00:00:00 2001 From: Ankur Datta <64993082+ankur-arch@users.noreply.github.com> Date: Sat, 15 Nov 2025 06:45:44 +0600 Subject: [PATCH 6/6] feat: add new features --- .../325-prisma-config-reference.mdx | 528 +++++++++++------- 1 file changed, 339 insertions(+), 189 deletions(-) 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 c81cd8e241..342eae5fc0 100644 --- a/content/200-orm/500-reference/325-prisma-config-reference.mdx +++ b/content/200-orm/500-reference/325-prisma-config-reference.mdx @@ -9,25 +9,25 @@ sidebar_label: "Prisma Config" The Prisma Config file configures the Prisma CLI, including subcommands like `migrate` and `studio`, using TypeScript. +:::info[Prisma ORM v7 changes] + +Starting with Prisma ORM v7, when you run `prisma init`, a `prisma.config.ts` file is automatically created. The database connection URL is now configured in this file instead of in the `schema.prisma` file. See [Using environment variables](#using-environment-variables) for setup details. + +::: + You can define your config in either of two ways: - Using the `defineConfig` helper: ```ts - import path from "node:path"; + import 'dotenv/config' import { defineConfig, env } from "prisma/config"; export default defineConfig({ - schema: path.join("prisma", "schema.prisma"), + schema: 'prisma/schema.prisma', migrations: { - path: path.join("db", "migrations"), - }, - views: { - path: path.join("db", "views"), - }, - typedSql: { - path: path.join("db", "queries"), + path: 'prisma/migrations', + seed: 'tsx prisma/seed.ts', }, - engine: "classic", datasource: { url: env("DATABASE_URL") } @@ -36,21 +36,16 @@ You can define your config in either of two ways: - Using TypeScript's `satisfies` operator with the `PrismaConfig` type: ```ts - import path from "node:path"; + import 'dotenv/config' import type { PrismaConfig } from "prisma"; + import { env } from "prisma/config"; export default { - schema: path.join("db", "schema.prisma"), + schema: "prisma/schema.prisma", migrations: { - path: path.join("db", "migrations"), + path: "prisma/migrations", + seed: 'tsx prisma/seed.ts', }, - views: { - path: path.join("db", "views"), - }, - typedSql: { - path: path.join("db", "queries"), - }, - engine: "classic", datasource: { url: env("DATABASE_URL") } @@ -66,22 +61,12 @@ export declare type PrismaConfig = { // Whether features with an unstable API are enabled. experimental: { - adapter: boolean; externalTables: boolean; - studio: boolean; }, // The path to the schema file, or path to a folder that shall be recursively searched for *.prisma files. schema?: string; - // The Driver Adapter used for Prisma CLI. - adapter?: () => Promise; - - // Configuration for Prisma Studio. - studio?: { - adapter: () => Promise; - }; - // Configuration for Prisma migrations. migrations?: { path: string; @@ -98,19 +83,29 @@ export declare type PrismaConfig = { typedSql?: { path: string; }; - // Depending on the choice, you must provide either a `datasource` object or driver adapter - engine: 'classic' | 'js' - // If using the classic engine, datasource sets the database url, shadowDatabaseUrl, or directURL + // Database connection configuration datasource?: { url: string; - directUrl?: string; shadowDatabaseUrl?: string; } }; ``` +:::note[Prisma ORM v6.19 and earlier] + +In Prisma ORM v6.19 and earlier, the configuration interface also included: +- `experimental.adapter` and `experimental.studio` flags +- `adapter` property for configuring driver adapters +- `studio` property for Prisma Studio configuration +- `datasource.directUrl` property for direct database connections +- `engine` property for choosing between `classic` and `js` engines + +These have been removed in Prisma ORM v7. See the individual property sections below for migration guidance. + +::: + ## Supported file extensions Prisma Config files can be named as `prisma.config.*` or `.config/prisma.*` with the extensions `js`, `ts`, `mjs`, `cjs`, `mts`, or `cts`. Other extensions are supported to ensure compatibility with different TypeScript compiler settings. @@ -133,80 +128,6 @@ Configures how Prisma ORM locates and loads your schema file(s). Can be a file o | -------- | -------- | -------- | ---------------------------------------------- | | `schema` | `string` | No | `./prisma/schema.prisma` and `./schema.prisma` | -### `adapter` - -A function that returns a Prisma driver adapter instance which is used by the Prisma CLI to run migrations. The function should return a `Promise` that resolves to a valid Prisma driver adapter. - -| Property | Type | Required | Default | -| ----------------- | -------------------------------------------------------------- | -------- | ------- | -| `adapter` | `() => Promise` | No | none | - -Example using the Prisma ORM D1 driver adapter: - -```ts -import path from "node:path"; -import type { PrismaConfig } from "prisma"; -import { PrismaD1 } from "@prisma/adapter-d1"; - -export default { - experimental: { - adapter: true - }, - schema: path.join("prisma", "schema.prisma"), - async adapter() { - return new PrismaD1({ - CLOUDFLARE_D1_TOKEN: process.env.CLOUDFLARE_D1_TOKEN, - CLOUDFLARE_ACCOUNT_ID: process.env.CLOUDFLARE_ACCOUNT_ID, - CLOUDFLARE_DATABASE_ID: process.env.CLOUDFLARE_DATABASE_ID, - }); - }, -} satisfies PrismaConfig; -``` - -:::note - -As of [Prisma ORM v6.11.0](https://github.com/prisma/prisma/releases/tag/6.11.0), the D1 adapter has been renamed from `PrismaD1HTTP` to `PrismaD1`. - -::: - -### `studio` - -Configures how Prisma Studio connects to your database. See sub-options below for details. - -| Property | Type | Required | Default | -| -------- | -------- | -------- | ------- | -| `studio` | `object` | No | none | - -#### `studio.adapter` - -A function that returns a Prisma driver adapter instance. The function receives an `env` parameter containing environment variables and should return a `Promise` that resolves to a valid Prisma driver adapter. - -| Property | Type | Required | Default | -| ----------------- | -------------------------------------------------------------- | -------- | ------- | -| `studio.adapter ` | `(env: Env) => Promise` | No | none | - -Example using the Prisma ORM LibSQL driver adapter: - -```ts -import type { PrismaConfig } from "prisma"; - -export default { - experimental: { - studio: true - }, - studio: { - adapter: async (env: Env) => { - const { PrismaLibSQL } = await import("@prisma/adapter-libsql"); - const { createClient } = await import("@libsql/client"); - - const libsql = createClient({ - url: env.DOTENV_PRISMA_STUDIO_LIBSQL_DATABASE_URL, - }); - return new PrismaLibSQL(libsql); - }, - }, -} satisfies PrismaConfig; -``` ### `tables.external` and `enums.external` @@ -220,9 +141,17 @@ These options declare tables and enums in your database that are **managed exter **Example:** ```ts -import { defineConfig } from "prisma/config"; +import 'dotenv/config' +import { defineConfig, env } from "prisma/config"; export default defineConfig({ + schema: 'prisma/schema.prisma', + migrations: { + path: 'prisma/migrations', + }, + datasource: { + url: env('DATABASE_URL'), + }, experimental: { externalTables: true, }, @@ -256,11 +185,17 @@ This option allows you to define a script that Prisma runs to seed your database **Example:** ```ts -import { defineConfig } from "prisma/config"; +import 'dotenv/config' +import { defineConfig, env } from "prisma/config"; export default defineConfig({ + schema: 'prisma/schema.prisma', migrations: { - seed: `tsx db/seed.ts`, + path: 'prisma/migrations', + seed: 'tsx db/seed.ts', + }, + datasource: { + url: env('DATABASE_URL'), }, }); ``` @@ -276,20 +211,26 @@ This option allows you to define SQL statements that Prisma runs on the **shadow **Example:** ```ts -import { defineConfig } from "prisma/config"; +import 'dotenv/config' +import { defineConfig, env } from "prisma/config"; export default defineConfig({ + schema: 'prisma/schema.prisma', + migrations: { + path: 'prisma/migrations', + initShadowDb: ` + CREATE TABLE public.users (id SERIAL PRIMARY KEY); + `, + }, + datasource: { + url: env('DATABASE_URL'), + }, experimental: { externalTables: true, }, tables: { external: ["public.users"], }, - migrations: { - initShadowDb: ` - CREATE TABLE public.users (id SERIAL PRIMARY KEY); - `, - }, }); ``` @@ -317,37 +258,178 @@ Enables specific experimental features in the Prisma CLI. | Property | Type | Required | Default | | ---------------- | --------- | -------- | ------- | -| `adapter` | `boolean` | No | `false` | | `externalTables` | `boolean` | No | `false` | -| `studio` | `boolean` | No | `false` | Example: ```ts -import { defineConfig } from "prisma/config"; +import 'dotenv/config' +import { defineConfig, env } from "prisma/config"; export default defineConfig({ + schema: 'prisma/schema.prisma', + migrations: { + path: 'prisma/migrations', + }, + datasource: { + url: env('DATABASE_URL'), + }, experimental: { - adapter: true, externalTables: true, - studio: true, }, - schema: "prisma/schema.prisma", }); ``` :::note -If you use features like `adapter`, `studio` or `externalTables` without enabling the corresponding experimental flag, Prisma will throw an error: +If you use the `externalTables` feature without enabling the experimental flag, Prisma will throw an error: ```terminal -Failed to load config file "~" as a TypeScript/JavaScript module. Error: Error: The `studio` configuration requires `experimental.studio` to be set to `true`. +Failed to load config file "~" as a TypeScript/JavaScript module. Error: Error: The `externalTables` configuration requires `experimental.externalTables` to be set to `true`. +``` + +::: + +:::info[Prisma ORM v6.19 and earlier] + +In Prisma ORM v6.19 and earlier, the `experimental` object also included `adapter` and `studio` flags. These have been removed in Prisma ORM v7. See the [`adapter`](#adapter-removed) and [`studio`](#studio-removed) sections for details. + +::: + + +### `datasource.url` + +Connection URL including authentication info. Most connectors use [the syntax provided by the database](/orm/reference/connection-urls#format). + +:::info[Prisma ORM v7 changes] + +In Prisma ORM v7, the `url` field is configured in `prisma.config.ts` instead of in [the `datasource` block of your `schema.prisma`](/orm/prisma-schema/overview/data-sources) file. When you run `prisma init`, the generated `schema.prisma` file will not include a `url` property in the `datasource` block. + +For Prisma ORM v6.19 and earlier, the `url` field remains in the `schema.prisma` file's `datasource` block. + +::: + +| Property | Type | Required | Default | +| -------- | ------------------ | -------- | ----------------- | +| `datasource.url` | `string` | Yes | `''` | + +**Example:** + +```ts +import 'dotenv/config' +import { defineConfig, env } from "prisma/config"; + +export default defineConfig({ + schema: 'prisma/schema.prisma', + migrations: { + path: 'prisma/migrations', + }, + datasource: { + url: env('DATABASE_URL'), + }, +}); +``` + + +### `datasource.shadowDatabaseUrl` + +Connection URL to the shadow database used by Prisma Migrate. Allows you to use a cloud-hosted database as the shadow database. + +:::info[Prisma ORM v7 changes] + +In Prisma ORM v7, the `shadowDatabaseUrl` field is configured in `prisma.config.ts` instead of in the `datasource` block of your `schema.prisma` file. + +For Prisma ORM v6.19 and earlier, the `shadowDatabaseUrl` field remains in the `schema.prisma` file's `datasource` block. + +::: + +| Property | Type | Required | Default | +| -------- | ------------------ | -------- | ----------------- | +| `datasource.shadowDatabaseUrl` | `string` | No | `''` | + + +### `datasource.directUrl` (removed) + +:::warning[Removed in Prisma ORM v7] + +The `datasource.directUrl` property has been removed in Prisma ORM v7 in favor of the [`url` property](#datasourceurl). + +::: + +
+For Prisma ORM v6.19 and earlier + +Connection URL for direct connection to the database. + +If you use a connection pooler URL in the `url` argument (for example, 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 | +| -------- | ------------------ | -------- | ----------------- | +| `datasource.directUrl` | `string` | No | `''` | + +
+ + +### `adapter` (removed) + +:::warning[Removed in Prisma ORM v7] + +The `adapter` property has been removed in Prisma ORM v7. Migrations for driver adapters work automatically without additional configuration in `prisma.config.ts` as of Prisma ORM v7. + +::: + +
+For Prisma ORM v6.19 and earlier + +A function that returns a Prisma driver adapter instance which is used by the Prisma CLI to run migrations. The function should return a `Promise` that resolves to a valid Prisma driver adapter. + +| Property | Type | Required | Default | +| ----------------- | -------------------------------------------------------------- | -------- | ------- | +| `adapter` | `() => Promise` | No | none | + +Example using the Prisma ORM D1 driver adapter: + +```ts +import path from "node:path"; +import type { PrismaConfig } from "prisma"; +import { PrismaD1 } from "@prisma/adapter-d1"; + +export default { + experimental: { + adapter: true + }, + engine: "js", + schema: path.join("prisma", "schema.prisma"), + async adapter() { + return new PrismaD1({ + CLOUDFLARE_D1_TOKEN: process.env.CLOUDFLARE_D1_TOKEN, + CLOUDFLARE_ACCOUNT_ID: process.env.CLOUDFLARE_ACCOUNT_ID, + CLOUDFLARE_DATABASE_ID: process.env.CLOUDFLARE_DATABASE_ID, + }); + }, +} satisfies PrismaConfig; ``` +:::note + +As of [Prisma ORM v6.11.0](https://github.com/prisma/prisma/releases/tag/6.11.0), the D1 adapter has been renamed from `PrismaD1HTTP` to `PrismaD1`. + ::: +
+ +### `engine` (removed) + +:::warning[Removed in Prisma ORM v7] + +The `engine` property has been removed in Prisma ORM v7. -### `engine` +::: + +
+For Prisma ORM v6.19 and earlier Configure the schema engine your project should use. @@ -355,8 +437,7 @@ Configure the schema engine your project should use. | -------- | ------------------ | -------- | ----------------- | | `engine` | `classic` or `js` | No | `classic` | - By default it is set to use the classic engine, which requires that `datasource` be set - in your `prisma.config.ts`. +By default it is set to use the classic engine, which requires that `datasource` be set in your `prisma.config.ts`. ```ts import path from "node:path"; @@ -370,48 +451,65 @@ export default defineConfig({ }); ``` -### `datasource.url` +
-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). -::: +### `studio` (removed) -| Property | Type | Required | Default | -| -------- | ------------------ | -------- | ----------------- | -| `datasource.url` | `string` | Yes | `''` | +:::warning[Removed in Prisma ORM v7] +The `studio` property has been removed in Prisma ORM v7. To run Prisma Studio, use: -### `datasource.shadowDatabaseUrl` +```terminal +npx prisma studio --config ./prisma.config.ts +``` -Connection URL to the shadow database used by Prisma Migrate. Allows you to use a cloud-hosted database as the shadow database +Prisma Studio now uses the connection configuration from the `datasource` property automatically. See the [Prisma Studio documentation](/orm/reference/prisma-cli-reference#studio) for more details. -:::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 | `''` | +
+For Prisma ORM v6.19 and earlier +Configures how Prisma Studio connects to your database. See sub-options below for details. -### `datasource.directUrl` +| Property | Type | Required | Default | +| -------- | -------- | -------- | ------- | +| `studio` | `object` | No | none | -Connection URL for direct connection to the database. +#### `studio.adapter` -:::note -Replaces the deprecated `directUrl` field in the Prisma schema `datasource` block (Prisma ORM v7 and later). -::: +A function that returns a Prisma driver adapter instance. The function receives an `env` parameter containing environment variables and should return a `Promise` that resolves to a valid Prisma driver adapter. -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 | +| ----------------- | -------------------------------------------------------------- | -------- | ------- | +| `studio.adapter ` | `(env: Env) => Promise` | No | none | -| Property | Type | Required | Default | -| -------- | ------------------ | -------- | ----------------- | -| `datasource.directUrl` | `string` | No | `''` | +Example using the Prisma ORM LibSQL driver adapter: +```ts +import type { PrismaConfig } from "prisma"; +export default { + experimental: { + studio: true + }, + engine: "js", + studio: { + adapter: async (env: Env) => { + const { PrismaLibSQL } = await import("@prisma/adapter-libsql"); + const { createClient } = await import("@libsql/client"); + const libsql = createClient({ + url: env.DOTENV_PRISMA_STUDIO_LIBSQL_DATABASE_URL, + }); + return new PrismaLibSQL(libsql); + }, + }, +} satisfies PrismaConfig; +``` + +
## Common patterns @@ -422,75 +520,108 @@ To get started with Prisma Config, create a `prisma.config.ts` file in your proj Using `defineConfig`: ```ts -import { defineConfig } from "prisma/config"; +import 'dotenv/config' +import { defineConfig, env } from "prisma/config"; -export default defineConfig({}); +export default defineConfig({ + schema: 'prisma/schema.prisma', + migrations: { + path: 'prisma/migrations', + }, + datasource: { + url: env('DATABASE_URL'), + }, +}); ``` Using TypeScript types: ```ts +import 'dotenv/config' import type { PrismaConfig } from "prisma"; +import { env } from "prisma/config"; -export default {} satisfies PrismaConfig; +export default { + schema: 'prisma/schema.prisma', + migrations: { + path: 'prisma/migrations', + }, + datasource: { + url: env('DATABASE_URL'), + }, +} satisfies PrismaConfig; ``` ### Using environment variables -When using `prisma.config.ts`, environment variables from `.env` files are not automatically loaded. Using `tsx`, you can pass a `--env-file` flag and that will automatically add those values to `process.env` +:::info[Prisma ORM v7 changes] -If using Node or Deno: +In Prisma ORM v7, when you run `prisma init`, the generated `prisma.config.ts` file includes `import 'dotenv/config'` by default. You must install the `dotenv` package to use environment variables. + +::: + +When using `prisma.config.ts`, environment variables from `.env` files need to be loaded explicitly. There are several approaches depending on your runtime and Node version: + +#### Using dotenv (Recommended for Prisma ORM v7) + +1. Install the `dotenv` package: ```terminal -tsx --env-file=.env src/index.ts -tsx watch --env-file=.env --env-file=.local.env src/index.ts -tsx --env-file=.env ./prisma/seed.ts +npm install dotenv ``` -For Bun, `.env` files are automatically loaded. +2. Import `dotenv/config` at the top of your `prisma.config.ts` file: -For accessing environment variables within `prisma.config.ts`, use the `env()` helper function to -provide a type-safe way of accessing that variable: - -```tsx -import path from "node:path"; +```ts +import 'dotenv/config' import { defineConfig, env } from "prisma/config"; -type Env = { - DATABASE_URL: string -} export default defineConfig({ - engine: "classic", + schema: 'prisma/schema.prisma', + migrations: { + path: 'prisma/migrations', + seed: 'tsx prisma/seed.ts', + }, datasource: { - url: env('DATABASE_URL'), + url: env('DATABASE_URL'), }, - schema: path.join("prisma", "schema.prisma"), }); ``` -For releases of Node before v20, you'll need to: +#### Using Node.js v20+ or tsx with --env-file flag -1. Install the `dotenv` package: +If using Node.js v20+ or `tsx`, you can pass a `--env-file` flag to automatically load environment variables: ```terminal -npm install dotenv +tsx --env-file=.env src/index.ts +tsx watch --env-file=.env --env-file=.local.env src/index.ts +tsx --env-file=.env ./prisma/seed.ts ``` -2. Import `dotenv/config` in your config file: +#### Using Bun + +For Bun, `.env` files are automatically loaded without additional configuration. + +#### Type-safe environment variables + +Use the `env()` helper function to provide type-safe access to environment variables: ```ts -import "dotenv/config"; +import 'dotenv/config' import { defineConfig, env } from "prisma/config"; type Env = { DATABASE_URL: string } + export default defineConfig({ - engine: "classic", + schema: 'prisma/schema.prisma', + migrations: { + path: 'prisma/migrations', + }, datasource: { - url: env('DATABASE_URL'), + url: env('DATABASE_URL'), }, - schema: path.join("prisma", "schema.prisma"), }); ``` @@ -611,12 +742,23 @@ prisma validate --config ./path/to/myconfig.ts ## Loading environment variables +:::info[Prisma ORM v7 changes] + + +In Prisma ORM v7, `prisma init` generates a `prisma.config.ts` file automatically. To load environment variables with `dotenv`, do the following: + +1. Install the `dotenv` package. +2. Add `import 'dotenv/config'` at the top of your `prisma.config.ts` file. + +This is required for Prisma to read values from your `.env` file. +::: + 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: +1. Install the `dotenv` package: ```bash - npm install dotenv --save-dev + npm install dotenv ``` 2. Create a `.env` file in your project root (if it doesn't exist) and add your database connection string: @@ -625,15 +767,23 @@ To load environment variables in your Prisma application, you can use the `prism DATABASE_URL="your_database_connection_string_here" ``` -3. Update your `prisma.config.ts` file in your project root: +3. Ensure your `prisma.config.ts` file imports `dotenv/config` at the top: - ```ts - import "dotenv/config"; + ```ts file=prisma.config.ts + // add-start + import 'dotenv/config' + // add-end import { defineConfig, env } from "prisma/config"; export default defineConfig({ - datasource: { - url: env("DATABASE_URL"), - }, + schema: 'prisma/schema.prisma', + migrations: { + path: 'prisma/migrations', + seed: 'tsx prisma/seed.ts', + }, + datasource: { + url: env("DATABASE_URL"), + }, }); - ``` \ No newline at end of file + ``` +