diff --git a/apps/docs/content/docs/(index)/prisma-compute/deploy.mdx b/apps/docs/content/docs/(index)/prisma-compute/deploy.mdx index ec37a177921..271e8f8a73a 100644 --- a/apps/docs/content/docs/(index)/prisma-compute/deploy.mdx +++ b/apps/docs/content/docs/(index)/prisma-compute/deploy.mdx @@ -13,7 +13,7 @@ Start from wherever you are: - **You're starting from scratch.** [Declare a new app](#start-from-scratch) and run it locally, then deploy it. - **You already have an app.** [Add a declaration around your server code](#bring-an-app-you-already-have), then deploy it. -Both paths meet in the same [deploy step](#2-deploy), because Composer treats every app the same way. A deployed app becomes a **project**, deploying with no flags targets **production**, and `--stage ` deploys an isolated copy of the whole app as a [preview branch](/compute/branching) of the same project. Local runs never talk to the platform, so you need credentials only when you deploy. For the platform's resource model, see [Compute](/compute#the-model). +Both paths meet in the same [deploy step](#2-deploy), because Composer treats every app the same way. A deployed app becomes a **project**, deploying with no flags targets the **production** environment, and `--environment ` deploys an isolated copy of the whole app as a [preview branch](/compute/branching) of the same project. Local runs never talk to the platform, so you need credentials only when you deploy. For the platform's resource model, see [Compute](/compute#the-model). ## Prerequisites @@ -235,15 +235,15 @@ You can also inspect everything in the [Console](https://pris.ly/pdp): projects, ## 4. Ship changes and environments -Re-deploying is idempotent: build again, deploy again, and the platform applies the difference instead of recreating everything. That includes removals: delete a provision from your module and the next deploy deletes the resource; see [Removing resources](/composer/deploying#removing-resources). Production and previews are separated by stages: +Re-deploying is idempotent: build again, deploy again, and the platform applies the difference instead of recreating everything. That includes removals: delete a provision from your module and the next deploy deletes the resource; see [Removing resources](/composer/deploying#removing-resources). Production and previews are separate environments: ```npm -npx prisma deploy # production -npx prisma deploy --stage staging # a persistent staging environment -npx prisma deploy --stage pr-42 # one environment per PR +npx prisma deploy # production +npx prisma deploy --environment staging # a persistent staging environment +npx prisma deploy --environment pr-42 # one environment per PR ``` -A stage is a complete, isolated copy of the app: its own services, databases, and configuration, sharing only the code with production. In platform terms it is a [preview branch](/compute/branching) of the same project. Tearing a stage down needs the control API with service-token credentials, or a branch deletion in the Console; see [Destroying](/composer/deploying#destroying). [Deploying](/composer/deploying) covers CI, deploy state, and teardown in full. +Each environment is a complete, isolated copy of the app: its own services, databases, and configuration, sharing only the code with the others. In platform terms, `production` is the project's default branch, and any other environment is a [preview branch](/compute/branching) of the same project with that name. Tearing an environment down needs the control API with service-token credentials, or a branch deletion in the Console; see [Destroying](/composer/deploying#destroying). [Deploying](/composer/deploying) covers CI, deploy state, and teardown in full. ## Hand it to your agent @@ -273,5 +273,5 @@ Build a Bun API with a /todos endpoint backed by an in-memory list as a Prisma C - [Composer getting started](/composer/getting-started): the two-service version, with a typed contract between services. - [Databases](/composer/databases): give a service a Prisma Postgres database, plain or typed by a Prisma ORM contract. -- [Deploying](/composer/deploying): stages, CI, deploy state, and teardown. +- [Deploying](/composer/deploying): environments, CI, deploy state, and teardown. - [Local development](/local-development): run the app, database, and storage on your machine with the runtime you deploy. diff --git a/apps/docs/content/docs/(index)/prisma-orm/from-scratch.mdx b/apps/docs/content/docs/(index)/prisma-orm/from-scratch.mdx index ffff8efcc3f..d4046aa8b6f 100644 --- a/apps/docs/content/docs/(index)/prisma-orm/from-scratch.mdx +++ b/apps/docs/content/docs/(index)/prisma-orm/from-scratch.mdx @@ -47,7 +47,7 @@ npm install --save-dev prisma tsx typescript `temporal-polyfill` is a peer dependency of `@prisma/orm-postgres` too. It adds `Temporal`, the newer JavaScript date and time API, to runtimes such as Node.js 24 that do not have it built in. npm installs it for you, but with Yarn you add it yourself. -The two Prisma packages have different version numbers, for example `prisma` 8.0.0-rc.28 and `@prisma/orm-postgres` 8.0.0-rc.21. That is normal, and any two `latest` versions work together. +The two Prisma packages have different version numbers, for example `prisma` 8.0.0-rc.30 and `@prisma/orm-postgres` 8.0.0-rc.21. That is normal, and any two `latest` versions work together. ## 2. Create the config file and `.env` diff --git a/apps/docs/content/docs/ai/tools/skills.mdx b/apps/docs/content/docs/ai/tools/skills.mdx index d6b3f8b54ae..ea7d6d54047 100644 --- a/apps/docs/content/docs/ai/tools/skills.mdx +++ b/apps/docs/content/docs/ai/tools/skills.mdx @@ -131,7 +131,7 @@ npx prisma skills sync If you want the skill without installing the package, `npx skills add prisma/composer` still reads the [prisma/composer](https://github.com/prisma/composer) repository. That is a fallback: nothing keeps a copy installed that way up to date. -It covers the whole Composer story: the mental model (Modules, `compute()`, `service.load()`), RPC contracts, databases, the first-party Modules for scheduled jobs, object storage, and event streams, config params and secrets, testing, and deploying with stages. Install it before your agent writes Composer code so it works from the current authoring API instead of inventing one. +It covers the whole Composer story: the mental model (Modules, `compute()`, `service.load()`), RPC contracts, databases, the first-party Modules for scheduled jobs, object storage, and event streams, config params and secrets, testing, and deploying to environments. Install it before your agent writes Composer code so it works from the current authoring API instead of inventing one. ## Useful commands diff --git a/apps/docs/content/docs/cli/deploy.mdx b/apps/docs/content/docs/cli/deploy.mdx index 8cd4bb06f47..57b90b4c9cc 100644 --- a/apps/docs/content/docs/cli/deploy.mdx +++ b/apps/docs/content/docs/cli/deploy.mdx @@ -1,9 +1,9 @@ --- title: deploy -description: Deploy a Composer application to Prisma Compute, to production or an isolated stage. +description: Deploy a Composer application to Prisma Compute, to production or another environment. url: /cli/deploy metaTitle: deploy | Prisma CLI -metaDescription: Complete reference for the prisma deploy command, including stages, credentials, CI reports, and the in-process control API. +metaDescription: Complete reference for the prisma deploy command, including environments, credentials, CI reports, and the in-process control API. --- `deploy` deploys a [Prisma Composer](/composer) application to [Prisma Compute](/compute). It loads the module whose default export is the application root, named by `entry` in the `composer` section of `prisma.config.ts`, typically `./module.ts`. The command streams the deploy pipeline's own output to the terminal. @@ -20,7 +20,8 @@ The `deploy` command does not build your application. Run your build command bef ```npm npx prisma deploy -npx prisma deploy --stage feat-auth +npx prisma deploy --environment feat-auth +npx prisma deploy list --environment feat-auth ``` ## Flags @@ -29,10 +30,22 @@ npx prisma deploy --stage feat-auth | --- | --- | | `--entry ` | Deploy the app from this module instead of the `entry` in `prisma.config.ts` | | `--name ` | Override the application name for this deploy. It defaults to the name of the exported application, and that name selects the project in your workspace: a project this module deployed before is reused, and a same-name project whose hosted state cannot be verified stops the deploy with `HostedStateBootstrapError`, so pass `--name` when the default would land in a project you did not mean to deploy into | -| `--stage ` | Deploy scope to target; omit for production | -| `--report ` | Write the deploy's outcome as JSON to this path: resources, preview URLs, and the failure cause. Also settable as `PRISMA_COMPOSER_REPORT_FILE` | +| `--environment ` | The environment to deploy to. Defaults to `production`. Any other name is a complete, isolated copy of the app, such as `staging` or one per pull request. On Prisma Cloud, `production` is the project's default branch and any other name is a preview branch with that name | +| `--report ` | Write the deploy's outcome as JSON to this path: resources, preview URLs, and the failure cause. The report's `environment` field names the environment it deployed. Also settable as `PRISMA_COMPOSER_REPORT_FILE` | | `--build-id ` | Join the deploy record your CI already created rather than letting the target create one | +Upgrading from `--stage`: since `8.0.0-rc.30` the flag is `--environment`, and `--stage` fails with `CLI.COMMAND_MOVED`, naming the new flag. The `--report` file's `stage` field is now `environment`, and its `version` is `2`. Keep `@prisma/composer-prisma-cloud` on the same Composer version as the `prisma` CLI: an older one would read every environment as production, so the deploy refuses it with `DEPS.EXTENSION_INCOMPATIBLE` before it changes anything. + +## deploy list + +`deploy list` shows every node the app has deployed in an environment, the platform ID each one became and, for a service, its URL. It reads the environment on Prisma Cloud, so it works from any machine. Without `--environment` it lists `production`. It finds the app as `deploy` does, so run it where you run `deploy`, or pass the same `--name` and `--entry`. + +```npm +npx prisma deploy list --environment pr-42 +``` + +It fails with `DEPLOY.TARGET_NOT_FOUND` when the environment has nothing deployed. + ## Global flags The Prisma CLI's global flags also apply: `--format`, `--json`, `--log-level`, `--verbose`, `--quiet`, `--yes`, `--confirm`, `--interactive`, `--color`, and `--config`. @@ -48,16 +61,24 @@ The Prisma CLI's global flags also apply: `--format`, `--json`, `--log-level`, ` ## Tearing down and log tailing -The unified CLI has no `destroy` or `log` command. Both operations are available in-process through the control API below: `destroy` takes an explicit target (`{ kind: 'production' }` or `{ kind: 'stage', stage }`), and `log` tails a locally running application. +The unified CLI has no `destroy` or `log` command. Both operations are available in-process through the control API below. `destroy` takes the name of the environment to remove, and has no default: production is `environment: 'production'`, and a call without `environment` fails with `DEPLOY.ENVIRONMENT_REQUIRED`. `log` tails a locally running application. ## The control API Everything the CLI does is also callable in-process, from `@prisma/composer/control`: typed `deploy`, `destroy`, `dev`, and `log` operations that return structured results instead of printing and exiting: ```ts +import { fileURLToPath } from 'node:url'; import { deploy } from '@prisma/composer/control'; - -const result = await deploy({ entry: 'module.ts', stage: 'pr-42' }); +import prismaConfig from './prisma.config.ts'; + +const result = await deploy({ + environment: 'pr-42', // omit for production + config: { + value: prismaConfig.composer, + file: fileURLToPath(new URL('./prisma.config.ts', import.meta.url)), + }, +}); if (!result.ok) console.error(result.failure.message); ``` @@ -69,4 +90,4 @@ The operations authenticate with `PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID - [`dev`](/cli/dev): run the same application locally, with no credentials. - [Getting started](/composer/getting-started): the commands in a working flow. -- [Deploying](/composer/deploying): stages, CI, and what a deploy prints. +- [Deploying](/composer/deploying): environments, CI, and what a deploy prints. diff --git a/apps/docs/content/docs/cli/dev.mdx b/apps/docs/content/docs/cli/dev.mdx index 95f93082d86..0dac6af1012 100644 --- a/apps/docs/content/docs/cli/dev.mdx +++ b/apps/docs/content/docs/cli/dev.mdx @@ -16,6 +16,7 @@ Like [`deploy`](/cli/deploy), `dev` runs your *built* output, so build first. npx prisma dev npx prisma dev --fresh npx prisma dev --detach +npx prisma dev --environment test --fresh npx prisma dev url my-app.gateway npx prisma dev stop ``` @@ -26,7 +27,7 @@ npx prisma dev stop | --- | --- | | `dev` | Run the app on this machine and watch it for changes until you press `Ctrl-C` | | `dev url
` | Print where a service, database, or bucket of the app answers locally | -| `dev stop` | Stop the app that `prisma dev` last ran from this directory | +| `dev stop` | Stop the app's local copy in one environment | `dev url`, `dev stop`, and `--detach` are in `prisma` since `8.0.0-rc.24`. Check your version with `npx prisma --version`. @@ -36,21 +37,23 @@ npx prisma dev stop | --- | --- | | `--entry ` | Load the app from this module instead of the `entry` in `prisma.config.ts` | | `--name ` | Run the app under this name instead of the name its root module declares. A different name gets its own local services, databases, and buckets | -| `--fresh` | Before starting, delete this app's local services, databases, and buckets, with their data. Other apps run from the same directory keep theirs | +| `--environment ` | The environment to run as. Defaults to `dev`. Each environment is a separate local copy of the app, with its own services, databases, buckets, and ports, so a second one, such as `test`, runs alongside `dev` and leaves its data alone | +| `--fresh` | Before starting, delete this app's local services, databases, and buckets in the environment, with their data. Other apps and environments run from the same directory keep theirs | | `--detach` | Return once every service answers, and leave the app running without watching for changes. `prisma dev stop` stops it. Use it in scripts, agents, and CI | -`dev` needs no credentials or environment variables; local runs never talk to the platform. +`dev` needs no credentials; local runs never talk to the platform. It reads the secrets your services bind with `envSecret` from its environment variables: your shell, or a `.env` file that `prisma.config.ts` loads. A required secret that is unset or empty stops `dev` with an error naming it. See [Secrets](/composer/local-development#secrets). -When `dev` ends, by `Ctrl-C` or a failure, it stops the app's service processes and local Postgres servers. The emulators themselves keep running. Their data and ports are kept, so the next `dev` in this directory starts with the same ports and data. +When `dev` ends, by `Ctrl-C` or a failure, it stops the app's service processes and local Postgres servers. The emulators themselves keep running. Their data and ports are kept, so the next `dev` in this directory and environment starts with the same ports and data. Local state lives in `.prisma-composer/dev//`. -With `--detach`, `dev` prints the same `ready` line and service URLs as a foreground run, then exits with code `0` and leaves the app running. It does not pick up rebuilds: run `prisma dev --detach` again after a build, or run `prisma dev` in the foreground, which takes over the running app and watches it. If a detached start fails before every service answers, `dev` stops the whole app and exits non-zero. `--detach` combines with `--fresh` and `--name`. +With `--detach`, `dev` prints the same `ready` line and service URLs as a foreground run, then exits with code `0` and leaves the app running. It does not pick up rebuilds: run `prisma dev --detach` again after a build, or run `prisma dev` in the foreground, which takes over the running app and watches it. If a detached start fails before every service answers, `dev` stops the whole app and exits non-zero. `--detach` combines with `--fresh`, `--name`, and `--environment`. ## dev url -`dev url
` prints the local URL of one node of the app that `prisma dev` runs from the current directory. A node is a service, database, or bucket in the app, and its address is its path from the app's name, with dots between the names, such as `my-app.gateway` or, for a database inside a `catalog` module, `my-app.catalog.database`. +`dev url
` prints the local URL of one node of an app that `prisma dev` runs from the current directory. A node is a service, database, or bucket in the app, and its address is its path from the app's name, with dots between the names, such as `my-app.gateway` or, for a database inside a `catalog` module, `my-app.catalog.database`. ```npm npx prisma dev url my-app.gateway +npx prisma dev url my-app.gateway --environment test ``` ```text no-copy @@ -69,26 +72,28 @@ That line is for you to read. When standard output is a pipe or a file, or `$(.. url=$(npx prisma dev url my-app.gateway) && curl "$url" ``` -Run it from the directory you ran `prisma dev` in, while the app runs. It starts nothing: it reads what the last `prisma dev` in this directory recorded. With `--json`, it prints `{ address, kind, url, state }` instead. +Run it from the directory you ran `prisma dev` in, while the app runs. The first name of the address is the app, so `dev url` does not load your entry file. It reads the environment `dev` unless `--environment` names another, and it starts nothing: it reads what `prisma dev` recorded for that app and environment in this directory. With `--json`, it prints `{ address, kind, url, state }` instead. `dev url` prints a URL only for a node that is running, so something is listening at the URL it prints. Otherwise it fails with one of these codes: | Code | Meaning | | --- | --- | -| `DEV.NOT_STARTED_HERE` | `prisma dev` never ran in this directory | +| `DEV.NOT_STARTED_HERE` | `prisma dev` never ran that app in that environment in this directory | +| `DEV.ENVIRONMENT_NAME_MISMATCH` | The environment's folder belongs to an environment whose name differs only in case, such as `dev` for `--environment Dev` on macOS. Use the recorded name | | `DEV.ADDRESS_UNKNOWN` | The app has no node at that address. The message lists the addresses it has | | `DEV.EMULATOR_UNREACHABLE` | The emulator that runs the node is not running. Run `prisma dev` again, which starts it | -| `DEV.NOT_RUNNING` | The node exists but is not running. Usually it was stopped, by `prisma dev stop`, by `prisma dev` ending, or by running another app in this directory. A service that keeps crashing is reported this way too, with the path of its log | +| `DEV.NOT_RUNNING` | The node exists but is not running. Usually it was stopped, by `prisma dev stop` or by `prisma dev` ending. A service that keeps crashing is reported this way too, with the path of its log | ## dev stop -`dev stop` stops the app that `prisma dev` last ran from the current directory: its service processes and local database servers, as `Ctrl-C` does in a foreground `prisma dev`. +`dev stop` stops the app's local copy in one environment: its service processes and local database servers, as `Ctrl-C` does in a foreground `prisma dev`. It finds the app as `prisma dev` does, from your entry file or `--name`, and stops the environment `dev` unless `--environment` names another. Other apps and environments keep running. ```npm npx prisma dev stop +npx prisma dev stop --environment test ``` -Use it to stop an app started with `--detach`, or when `prisma dev` was killed without a chance to stop the app. It lists the services and databases it stopped. When nothing of the app was running, it prints `Nothing of was running.` and still exits with code `0`. Data and ports are kept, so the next `prisma dev` starts with the same ports and data. The emulators themselves keep running, because apps in other directories may use them. +Use it to stop an app started with `--detach`, or when `prisma dev` was killed without a chance to stop the app. If that app never ran in that environment here, it fails with `DEV.NOT_STARTED_HERE`. It lists the services and databases it stopped. When nothing of the app was running, it prints `Nothing of was running.` and still exits with code `0`. Data and ports are kept, so the next `prisma dev` starts with the same ports and data. The emulators themselves keep running, because apps in other directories may use them. ## Global flags diff --git a/apps/docs/content/docs/cli/emulator.mdx b/apps/docs/content/docs/cli/emulator.mdx index a62ff126878..0e168d1e093 100644 --- a/apps/docs/content/docs/cli/emulator.mdx +++ b/apps/docs/content/docs/cli/emulator.mdx @@ -8,7 +8,7 @@ metaDescription: Reference for the prisma emulator list command, which lists the Use `emulator` commands to inspect the local emulators. An emulator is a program on your machine that stands in for Prisma Compute, Prisma Postgres, or a bucket while [`prisma dev`](/cli/dev) runs a [Prisma Composer](/composer) app: one runs services, one runs Postgres databases, and one runs S3-compatible buckets. Each emulator holds instances, one for every service, database, or bucket that a `prisma dev` started, from any directory on the machine. -The emulators keep running after `prisma dev` ends. An instance keeps its port and data until `prisma dev --fresh`, run from the directory that started it, deletes it. There is no command yet to remove the instances of a directory you deleted. +The emulators keep running after `prisma dev` ends. An instance keeps its port and data until `prisma dev --fresh`, run from the directory and in the environment that started it, deletes it. There is no command yet to remove the instances of a directory you deleted. `emulator list` is in `prisma` since `8.0.0-rc.24`. @@ -27,7 +27,7 @@ npx prisma emulator list --json ## emulator list -`emulator list` works from any directory and needs no `prisma.config.ts`, because it describes the machine rather than one project. For each instance it shows the instance id, its URL, its state, and the node address and directory of the `prisma dev` that started it. +`emulator list` works from any directory and needs no `prisma.config.ts`, because it describes the machine rather than one project. For each instance it shows the instance id, its URL, its state, and the node address, directory, and environment of the `prisma dev` that started it. ```npm npx prisma emulator list @@ -35,15 +35,15 @@ npx prisma emulator list ```text no-copy ✔ Service emulator at http://127.0.0.1:4304 -└─ svc_56b2c1618f6488d2 http://localhost:3001 running my-app.gateway in /Users/ada/my-app +└─ svc_56b2c1618f6488d2 http://localhost:3001 running my-app.gateway in /Users/ada/my-app (dev) ✔ Database emulator at http://127.0.0.1:4305 -└─ db_7cff71f83ae35c90 postgres://…:51650/template1?sslmode=disable running my-app.catalog.database in /Users/ada/my-app +└─ db_7cff71f83ae35c90 postgres://…:51650/template1?sslmode=disable running my-app.catalog.database in /Users/ada/my-app (dev) ℹ Bucket emulator (not running) ``` An emulator that is not running is listed with no instances. One that is running but does not answer, or answers with an error, is shown with that error, and the other emulators are still listed. -When standard output is a pipe or a file, `emulator list` writes one line per instance, with six tab-separated fields: +When standard output is a pipe or a file, `emulator list` writes one line per instance, with seven tab-separated fields: | Field | Value | | --- | --- | @@ -53,8 +53,9 @@ When standard output is a pipe or a file, `emulator list` writes one line per in | 4 | The instance's state | | 5 | The address of the node it runs, such as `my-app.gateway` or `my-app.catalog.database` | | 6 | The directory `prisma dev` ran from | +| 7 | The environment `prisma dev` ran as, such as `dev` | -The last two fields are empty for an instance that the emulator holds without a record of which app started it. For example, to print the URL of every running instance started from the current directory: +The last three fields are empty for an instance that the emulator holds without a record of which app started it. The environment is also empty for an instance created by a Composer version that kept one local copy per directory. For example, to print the URL of every running instance started from the current directory: ```bash npx prisma emulator list | awk -F '\t' -v dir="$PWD" '$4 == "running" && $6 == dir { print $3 }' @@ -62,7 +63,7 @@ npx prisma emulator list | awk -F '\t' -v dir="$PWD" '$4 == "running" && $6 == d With `--json`, the result is `{ emulators: [{ kind, running, url, instances: [{ id, kind, url, state, labels }], error }] }`, where `url` is `null` for an emulator that is not running, and `error` is `null` unless the emulator is running but could not be listed. -There is no `prisma emulator start` or `prisma emulator stop` yet, so to stop one app's services and databases, run [`prisma dev stop`](/cli/dev#dev-stop) from that app's directory. +There is no `prisma emulator start` or `prisma emulator stop` yet, so to stop one app's services and databases, run [`prisma dev stop`](/cli/dev#dev-stop) from that app's directory, with the same `--environment`. ## Global flags diff --git a/apps/docs/content/docs/composer/apps-and-modules.mdx b/apps/docs/content/docs/composer/apps-and-modules.mdx index 82fdbc0b571..3c5e1664120 100644 --- a/apps/docs/content/docs/composer/apps-and-modules.mdx +++ b/apps/docs/content/docs/composer/apps-and-modules.mdx @@ -26,7 +26,7 @@ compute({ }); ``` -Dependencies and input are two deliberately separate channels with two separate accessors. A dependency is a live connection to another node; input is data, plain values and credentials together, declared as one schema (see [Service input](/composer/service-input)). Your code contains no configuration reads and no URLs, which is what makes every environment (production, a stage, a test) a different set of injected values and nothing more. +Dependencies and input are two deliberately separate channels with two separate accessors. A dependency is a live connection to another node; input is data, plain values and credentials together, declared as one schema (see [Service input](/composer/service-input)). Your code contains no configuration reads and no URLs, which is what makes every environment (production, staging, a test) a different set of injected values and nothing more. ## The root module @@ -88,7 +88,7 @@ const auth = provision(authModule, { provision(storefrontService, { deps: { auth: auth.rpc } }); ``` -A Module can also declare boundary `deps`: inputs its parent must supply, wired exactly like a service's. The root module you already have is the outermost Module, with no boundary at all. +A Module can also declare boundary `deps`: dependencies its parent must supply, wired exactly like a service's. The builder function receives them as `deps`, ready to pass into a `provision()` call. The root module you already have is the outermost Module, with no boundary at all. ## When to reach for a Module diff --git a/apps/docs/content/docs/composer/core-concepts.mdx b/apps/docs/content/docs/composer/core-concepts.mdx index 3273cbb8a3f..cf3df05e6ac 100644 --- a/apps/docs/content/docs/composer/core-concepts.mdx +++ b/apps/docs/content/docs/composer/core-concepts.mdx @@ -1,6 +1,6 @@ --- title: Core concepts -description: "The ideas every Composer declaration and command builds on: services, resources, Modules, ports, contracts, stages, and the deploy model." +description: "The ideas every Composer declaration and command builds on: services, resources, Modules, ports, contracts, environments, and the deploy model." url: /composer/core-concepts metaTitle: Prisma Composer core concepts metaDescription: Learn the core concepts behind Prisma Composer in one page. What services, resources, and Modules are, how ports and contracts wire them, and how deploys converge. @@ -88,7 +88,7 @@ const { products } = await catalog.listProducts({}); 2. **`envParam(NAME)`**: the value is read from a named platform variable per environment, so the same app reads different values in production and in a staging copy. 3. **`envSecret(NAME)`**: like `envParam`, but the value is a credential: redacted in output and never stored in deploy state. This is the only thing Composer calls a secret. -The split is what makes environments cheap: production, a staging stage, a local run, and a test all execute the same code with different injected values. See [Service input](/composer/service-input). +The split is what makes environments cheap: production, a staging environment, a local run, and a test all execute the same code with different injected values. See [Service input](/composer/service-input). ## Contracts @@ -106,17 +106,19 @@ npx prisma deploy Two consequences of convergence are worth naming. Removing a node from your module removes the deployed thing on the next deploy, because the topology is the source of truth. And tearing a whole environment down works through the same mechanism, via the `destroy` operation in `@prisma/composer/control`. See [Deploying](/composer/deploying) and the [`deploy` reference](/cli/deploy). -## Stages +## Environments -A **stage** is an environment name chosen at deploy time, never written in the topology. The same graph deploys anywhere: +An **environment** is a named place the app runs, chosen with `--environment` when you run a command, never written in the topology. The same graph deploys anywhere: ```npm -npx prisma deploy # production -npx prisma deploy --stage staging # a persistent staging environment -npx prisma deploy --stage pr-42 # one environment per PR +npx prisma deploy # production +npx prisma deploy --environment staging # a persistent staging environment +npx prisma deploy --environment pr-42 # one environment per PR ``` -Deploying with no `--stage` targets production, which lives at the project level. A named stage is a complete, isolated copy of the app, deployed as a [preview branch](/compute/branching) of the same project: its own services, its own databases, its own configuration. The only thing a stage shares with production is the code, which is exactly what the two-channel design promises: same topology, different injected values. +`deploy` without the flag deploys `production`, which is the project's default branch. Any other name is a complete, isolated copy of the app, deployed as a [preview branch](/compute/branching) of the same project with that name: its own services, its own databases, its own configuration. The only thing two environments share is the code, which is exactly what the two-channel design promises: same topology, different injected values. A module can still compute a value from the environment's name with `resolve()`; see [Values that differ per environment](/composer/service-input#values-that-differ-per-environment). + +`dev` runs as the environment `dev`, and `prisma dev --environment ` runs another, separate local copy of the app. ## Local development diff --git a/apps/docs/content/docs/composer/deploying.mdx b/apps/docs/content/docs/composer/deploying.mdx index edc868437dc..3505f091232 100644 --- a/apps/docs/content/docs/composer/deploying.mdx +++ b/apps/docs/content/docs/composer/deploying.mdx @@ -1,17 +1,18 @@ --- title: Deploying -description: Deploy a Prisma App to production or an isolated stage, run it in CI, and tear environments down safely. +description: Deploy a Prisma App to production or another isolated environment, run it in CI, and tear environments down safely. url: /composer/deploying metaTitle: Deploying | Prisma Composer -metaDescription: Deploy Prisma Composer apps to Prisma Compute with prisma deploy, use stages for isolated environments and per-PR previews, wire CI, and tear environments down safely. +metaDescription: Deploy Prisma Composer apps to Prisma Compute with prisma deploy, use environments for staging and per-PR previews, wire CI, and tear environments down safely. --- -`deploy` loads your entry file (the one whose default export is the root module, named by `entry` in the `composer` section of `prisma.config.ts`) and stands the whole app up on [Prisma Compute](/compute) and [Prisma Postgres](/postgres). You choose the target environment, production or an isolated **stage**, on the command line rather than in your code. Tearing an environment down is the `destroy` operation of the [control API](#driving-deploys-from-code). +`deploy` loads your entry file (the one whose default export is the root module, named by `entry` in the `composer` section of `prisma.config.ts`) and stands the whole app up on [Prisma Compute](/compute) and [Prisma Postgres](/postgres). You choose the **environment**, such as `production`, `staging`, or a preview such as `pr-42`, on the command line rather than in your code. Tearing an environment down is the `destroy` operation of the [control API](#driving-deploys-from-code). | You want to... | Run | | --- | --- | | Deploy to production | `npx prisma deploy` | -| Deploy an isolated environment | `npx prisma deploy --stage ` | +| Deploy another environment | `npx prisma deploy --environment ` | +| See what is deployed in an environment | `npx prisma deploy list --environment ` | | Deploy under a different app name | `npx prisma deploy --name demo-42` | ## Credentials @@ -27,7 +28,7 @@ In CI or any headless environment, use a service token instead. Set two environm - `PRISMA_SERVICE_TOKEN`: create a service token for your workspace in the [Prisma Console](https://console.prisma.io). - `PRISMA_WORKSPACE_ID`: in the workspace's settings. -A fresh checkout with those two variables set deploys successfully once the app's project exists. The very first deploy creates that project, and a new project needs a region: set it in the deploy config or in the environment, as described in the [`deploy` reference](/cli/deploy). Once the project exists it keeps its region, and later deploys, stages included, inherit it. The CLI finds or creates everything else. Keep the values out of the repo (an `.env` you source at deploy time, or CI secrets). When `PRISMA_SERVICE_TOKEN` is set it takes priority over any stored session. +A fresh checkout with those two variables set deploys successfully once the app's project exists. The very first deploy creates that project, and a new project needs a region: set it in the deploy config or in the environment, as described in the [`deploy` reference](/cli/deploy). Once the project exists it keeps its region, and later deploys, in every environment, inherit it. The CLI finds or creates everything else. Keep the values out of the repo (an `.env` you source at deploy time, or CI secrets). When `PRISMA_SERVICE_TOKEN` is set it takes priority over any stored session. ## Build first @@ -40,19 +41,33 @@ npx prisma deploy Deploy state records what is already provisioned, so a re-deploy applies the difference instead of recreating everything. The platform stores this state with the environment it describes, scoped to that environment's branch inside the app's project. It is not stored on your machine, so your laptop and CI see the same state. Concurrent deploys of the same environment take turns through a lease on that state. While one deploy holds the lease, a second deploy fails immediately with a message naming the holder. If a deploy crashes, its lease expires after about a minute, and the next deploy takes over. -## Production and stages + -Deploying with no `--stage` targets **production**. In platform terms, the app is a project (named after your root module), and production lives at the project level. The name is looked up in your workspace: a project this module deployed before is reused, and redeploying converges it. A project with the same name whose hosted state the CLI cannot identify or verify (one created outside this module's deploys, for example) stops the command with `HostedStateBootstrapError`. Use `--name` to deploy under a different name, or rename the module. +## Environments -`--stage ` deploys a complete, isolated copy of the app as a [preview branch](/compute/branching) of that same project: its own services, its own databases, its own configuration. The only thing a stage shares with production is the code. Composer's *stage* and Compute's *preview branch* are the same object seen from two tools, which is why the stage's variables are the branch's [environment variables](/compute/environment-variables): +An environment is a place the app runs, and every environment has a name. You choose it with `--environment` when you deploy. Without the flag, `deploy` deploys the environment `production`, exactly as `--environment production` does. In platform terms, the app is a project (named after your root module), and `production` is the project's default branch. The project name is looked up in your workspace: a project this module deployed before is reused, and redeploying converges it. A project with the same name whose hosted state the CLI cannot identify or verify (one created outside this module's deploys, for example) stops the command with `HostedStateBootstrapError`. Use `--name` to deploy under a different name, or rename the module. + +Any other name deploys a complete, isolated copy of the app as a [preview branch](/compute/branching) of that same project, with that name: its own services, its own databases, its own configuration. The deploy creates the branch if it does not exist. The only thing two environments share is the code. A Composer environment and a Compute branch are the same object seen from two tools, which is why an environment's variables are its branch's [environment variables](/compute/environment-variables): + +```npm +npx prisma deploy # production +npx prisma deploy --environment staging # a persistent staging environment +npx prisma deploy --environment pr-42 # one environment per PR +``` + +Re-deploying any environment is idempotent: it updates the resources in place. An environment name must be a valid git ref name; an invalid name fails with `DEPLOY.ENVIRONMENT_INVALID` rather than being renamed. The default branch's own name, such as `main`, is refused too, because it would be production under a second name. Deploy production as `production`, or with no flag. + +The services, databases, and wiring are the same in every environment; only configuration may differ. To compute a value from the environment's name, see [Values that differ per environment](/composer/service-input#values-that-differ-per-environment). + +### See what is deployed + +`deploy list` shows every node the app has deployed in an environment, the platform ID each one became and, for a service, its URL. It reads the environment on Prisma Cloud, so it works from any machine: ```npm -npx prisma deploy # production -npx prisma deploy --stage staging # a persistent staging environment -npx prisma deploy --stage pr-42 # one environment per PR +npx prisma deploy list --environment pr-42 ``` -Re-deploying any environment is idempotent: it updates the resources in place. A stage name must be a valid git ref name. An invalid name fails the deploy rather than being renamed. +Without `--environment` it lists `production`. See the [`deploy list` reference](/cli/deploy#deploy-list). ## What a deploy prints @@ -93,32 +108,42 @@ Two things a deploy never removes: ## Destroying -The unified CLI has no `destroy` command. Tear an environment down with the `destroy` operation from `@prisma/composer/control` (see [Driving deploys from code](#driving-deploys-from-code)). It requires an explicit target, `{ kind: 'stage', stage }` or `{ kind: 'production' }`, and there is no default, so a teardown always names what it destroys. Unlike the CLI, the control API does not read the session stored by `auth login`. Export `PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID` (see [Credentials](#credentials)) before running the script, or it stops with `environment variable PRISMA_WORKSPACE_ID is required`: +The unified CLI has no `destroy` command. Tear an environment down with the `destroy` operation from `@prisma/composer/control` (see [Driving deploys from code](#driving-deploys-from-code)). It requires the name of the environment to remove, even for production, which is `environment: 'production'`. There is no default, so a teardown always names what it destroys, and a call without `environment` fails with `DEPLOY.ENVIRONMENT_REQUIRED`. Unlike the CLI, the control API does not read the session stored by `auth login`. Export `PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID` (see [Credentials](#credentials)) before running the script, or it stops with `environment variable PRISMA_WORKSPACE_ID is required`: ```ts title="destroy-staging.ts" +import { fileURLToPath } from 'node:url'; import { destroy } from '@prisma/composer/control'; - -const result = await destroy({ entry: 'module.ts', target: { kind: 'stage', stage: 'staging' } }); +import prismaConfig from './prisma.config.ts'; + +const result = await destroy({ + environment: 'staging', // or 'production' + config: { + value: prismaConfig.composer, + file: fileURLToPath(new URL('./prisma.config.ts', import.meta.url)), + }, +}); if (!result.ok) throw new Error(`${result.failure.code}: ${result.failure.message}`); ``` +Like the [`log` script](/composer/local-development#logs), it reads the `composer` section of your `prisma.config.ts`, so it imports it and passes it as `config`. Run it from the directory you deploy from, for example with `node destroy-staging.ts`. + If you deployed under a different name with `--name`, pass the same `name` here so the operation finds the right project. -Destroying a stage removes its resources, then deletes its branch along with the stage's deploy state. Destroying production removes the resources and, if the project is empty afterwards, deletes the project too, so empty projects do not pile up in your workspace. A project still holding another stage's resources stays in place. Tearing down a stage that was never deployed fails with "nothing deployed". It does not provision one first. +Destroying any environment other than production removes its resources, then deletes its branch along with the environment's deploy state. Destroying production removes the resources and, if the project is empty afterwards, deletes the project too, so empty projects do not pile up in your workspace. A project still holding another environment's resources stays in place. Tearing down an environment that was never deployed fails with "nothing deployed". It does not provision one first. ## CI -On GitHub, connect the repository and add [prisma/cloud-deploy-action](https://github.com/prisma/cloud-deploy-action) to a workflow instead of scripting the deploy yourself. The action derives the target from the branch: the default branch deploys production, and every other branch deploys a stage named after it. Connected repositories authenticate through GitHub's OIDC tokens, without a stored secret. [Deploy on push](/compute/deploy-on-push) walks through the setup. +On GitHub, connect the repository and add [prisma/cloud-deploy-action](https://github.com/prisma/cloud-deploy-action) to a workflow instead of scripting the deploy yourself. The action derives the environment from the branch: the default branch deploys `production`, and every other branch deploys an environment named after it. Connected repositories authenticate through GitHub's OIDC tokens, without a stored secret. [Deploy on push](/compute/deploy-on-push) walks through the setup. Any other CI runs the same commands as your machine: set the two credential variables as CI secrets, build, and deploy. The per-PR environment pattern: ```npm -npx prisma deploy --stage "pr-$PR_NUMBER" # on push +npx prisma deploy --environment "pr-$PR_NUMBER" # on push ``` -When the PR closes, tear the stage down with the `destroy` operation, targeting `{ kind: 'stage', stage: 'pr-' }` from a small script. +When the PR closes, tear the environment down with the `destroy` operation from a small script that passes its name, `environment: 'pr-42'` for PR 42. -One extra step applies if your app binds input fields with `envSecret` or `envParam` (see [Service input](/composer/service-input)). Each stage stores its own copy of those platform variables. The deploying shell only seeds them. A fresh stage, such as a new `pr-42`, starts with none of them, so CI must export the values alongside the two credential variables. The first deploy then copies any missing values from the shell up to the stage. If a name is absent from both the platform and the shell, the deploy fails early and names the missing variable. +One extra step applies if your app binds input fields with `envSecret` or `envParam` (see [Service input](/composer/service-input)). Each environment stores its own copy of those platform variables. The deploying shell only seeds them. A fresh environment, such as a new `pr-42`, starts with none of them, so CI must export the values alongside the two credential variables. The first deploy then copies any missing values from the shell up to the environment. If a name is absent from both the platform and the shell, the deploy fails early and names the missing variable. ## When prisma.config.ts fails on an effect version conflict @@ -206,5 +231,5 @@ Everything the CLI does is also callable in-process, from `@prisma/composer/cont ## Next steps - [Local development](/composer/local-development): the same pipeline, no credentials. -- [Service input](/composer/service-input): how per-stage configuration and secrets travel. +- [Service input](/composer/service-input): how per-environment configuration and secrets travel. - [`deploy` command reference](/cli/deploy): every flag, plus the control API for destroy and log. diff --git a/apps/docs/content/docs/composer/getting-started.mdx b/apps/docs/content/docs/composer/getting-started.mdx index bb114809503..4be28965d45 100644 --- a/apps/docs/content/docs/composer/getting-started.mdx +++ b/apps/docs/content/docs/composer/getting-started.mdx @@ -325,13 +325,13 @@ A new project needs a region, so give it one before the first deploy, in the dep The CLI creates a project named `my-app` in your workspace (a project this module deployed before is reused; one whose hosted state the CLI cannot verify stops the deploy with `HostedStateBootstrapError`, so pass `--name ` in that case), provisions both services on Prisma Compute, points the gateway's `quotes` dependency at the deployed quotes service, and starts everything. The deploy finishes by printing what it made: your module names, the platform resource each became, and the public URLs. Open the gateway's URL and you get a quote. -Re-deploying is idempotent. For an isolated copy of the whole app, deploy a stage: +Re-deploying is idempotent. For an isolated copy of the whole app, deploy another environment: ```npm -npx prisma deploy --stage demo +npx prisma deploy --environment demo ``` -Tearing a stage down is the `destroy` operation of the [control API](/cli/deploy#the-control-api). That operation does not read your `auth login` session: it needs `PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID` in the environment, the same service-token credentials CI uses. Without them, delete the stage's branch in the [Console](https://console.prisma.io) instead. See [Deploying](/composer/deploying) for stages, CI, and teardown in full. +Tearing an environment down is the `destroy` operation of the [control API](/cli/deploy#the-control-api). That operation does not read your `auth login` session: it needs `PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID` in the environment, the same service-token credentials CI uses. Without them, delete the environment's branch in the [Console](https://console.prisma.io) instead. See [Deploying](/composer/deploying) for environments, CI, and teardown in full. ## Where to go next diff --git a/apps/docs/content/docs/composer/index.mdx b/apps/docs/content/docs/composer/index.mdx index fd7bf6188d2..498c6840677 100644 --- a/apps/docs/content/docs/composer/index.mdx +++ b/apps/docs/content/docs/composer/index.mdx @@ -79,7 +79,7 @@ TypeScript checks the wiring: a dependency bound to a producer with a different ## Design principles -Two choices shape the rest of the framework. First, application code does not read `process.env` or hardcode URLs. Dependencies arrive typed through `service.load()`, so production, an isolated stage, and a test all run the same code with different injected values. Second, Composer does not bundle or transform your code. You build with your own bundler, and the deploy assembles what you built. +Two choices shape the rest of the framework. First, application code does not read `process.env` or hardcode URLs. Dependencies arrive typed through `service.load()`, so production, a staging environment, and a test all run the same code with different injected values. Second, Composer does not bundle or transform your code. You build with your own bundler, and the deploy assembles what you built. ## Get started @@ -104,4 +104,4 @@ The `prisma-composer-core-concepts` skill documents the full authoring API, the ## What to read next -Start with [Apps and Modules](/composer/apps-and-modules) for how services, resources, and Modules compose into an app, then [Services and contracts](/composer/services-and-contracts) for the typed RPC between them. When you're ready to run something, [Local development](/composer/local-development) works with no cloud credentials, and [Deploying](/composer/deploying) covers production, stages, and CI. Check [Limitations](/composer/limitations) before committing to a design. +Start with [Apps and Modules](/composer/apps-and-modules) for how services, resources, and Modules compose into an app, then [Services and contracts](/composer/services-and-contracts) for the typed RPC between them. When you're ready to run something, [Local development](/composer/local-development) works with no cloud credentials, and [Deploying](/composer/deploying) covers production, other environments, and CI. Check [Limitations](/composer/limitations) before committing to a design. diff --git a/apps/docs/content/docs/composer/local-development.mdx b/apps/docs/content/docs/composer/local-development.mdx index d93d2aa3e0b..897064680c3 100644 --- a/apps/docs/content/docs/composer/local-development.mdx +++ b/apps/docs/content/docs/composer/local-development.mdx @@ -3,7 +3,7 @@ title: Local development description: Run the whole app on your machine with prisma dev, with no cloud credentials, and tail its logs through the control API. url: /composer/local-development metaTitle: Local development | Prisma Composer -metaDescription: Run a Prisma Composer app locally with prisma dev, find a running service's URL with prisma dev url, run the app in the background, and understand ports, warm restarts, --fresh, and local emulators. +metaDescription: Run a Prisma Composer app locally with prisma dev, find a running service's URL with prisma dev url, run the app in the background, run separate local environments, provide secrets, and understand ports, warm restarts, --fresh, and local emulators. --- One command brings your whole app up on your machine, every service, its databases and buckets, wired together, with no cloud credentials. `dev` runs the same pipeline a deploy runs, but against local stand-ins for Prisma Compute and Prisma Postgres, so what you run locally is what you ship. Logs are read separately, through the control API's `log` operation. @@ -15,10 +15,11 @@ One command brings your whole app up on your machine, every service, its databas | Run the app in the background | `npx prisma dev --detach` | | Stop the app | `Ctrl-C`, or `npx prisma dev stop` | | Start clean (wipe local data first) | `npx prisma dev --fresh` | +| Run a second, clean copy, for tests | `npx prisma dev --environment test --fresh` | | See everything running on this machine | `npx prisma emulator list` | | Watch the app's logs | the `log` operation (see [Logs](#logs)) | -`dev` loads your entry file, the one whose default export is the root module, named by `entry` in the `composer` section of `prisma.config.ts`. `deploy` loads the same file. No `PRISMA_*` variables are needed. Local dev never talks to the platform. +`dev` loads your entry file, the one whose default export is the root module, named by `entry` in the `composer` section of `prisma.config.ts`. `deploy` loads the same file. No `PRISMA_*` variables are needed. Local dev never talks to the platform. It runs as the environment `dev` unless you pass `--environment`, and each environment is a separate local copy of the app. `prisma dev url`, `prisma dev stop`, `--detach`, and `prisma emulator list` are in `prisma` since `8.0.0-rc.24`. Check your version with `npx prisma --version`. @@ -55,11 +56,11 @@ A service or database keeps its port from one `dev` to the next in the same dire [dev] service "gateway" now uses port 3004: its previous port 3001 is in use ``` -Because ports differ from one machine and one directory to the next, do not hard-code `localhost:3001` in scripts or notes. Ask `dev url` instead. +Because ports differ from one machine, directory, and environment to the next, do not hard-code `localhost:3001` in scripts or notes. Ask `dev url` instead. ## Find a running service -From another terminal in the same directory, ask where a service of the running app answers, by its address: +From another terminal in the same directory, ask where a service of the running app answers, by its address. It asks about the environment `dev`; pass `--environment` for another: ```npm npx prisma dev url my-app.gateway @@ -69,7 +70,7 @@ npx prisma dev url my-app.gateway ✔ The service my-app.gateway is running at http://localhost:3001 ``` -The address is the name `dev` printed next to the URL at startup. `dev url` also works for the app's databases and buckets: a database or bucket inside a module adds the module's name, such as `my-app.catalog.database`. For a database, `dev url` prints its connection string with the local credentials, and for a bucket, its S3 endpoint followed by `/`. +The address is the name `dev` printed next to the URL at startup. It starts with the app's name, which is how `dev url` knows which app you mean. `dev url` also works for the app's databases and buckets: a database or bucket inside a module adds the module's name, such as `my-app.catalog.database`. For a database, `dev url` prints its connection string with the local credentials, and for a bucket, its S3 endpoint followed by `/`. When its output is captured by `$(...)` or piped, `dev url` writes the URL alone, so a script can use it directly. Check the exit status first, so a failure does not run `curl` with an empty URL: @@ -77,7 +78,7 @@ When its output is captured by `$(...)` or piped, `dev url` writes the URL alone url=$(npx prisma dev url my-app.gateway) && curl "$url" ``` -`dev url` prints a URL only for a node that is running. When the app is stopped, or `prisma dev` never ran in this directory, it fails with an error code a script can check; the [`dev url` reference](/cli/dev#dev-url) lists them. +`dev url` prints a URL only for a node that is running. When the app is stopped, or `prisma dev` never ran that app in that environment in this directory, it fails with an error code a script can check; the [`dev url` reference](/cli/dev#dev-url) lists them. ## Run it in the background @@ -102,7 +103,7 @@ If a detached start fails before every service answers, `dev` stops the whole ap npx prisma dev stop ``` -`dev stop` stops the app that `prisma dev` last ran from this directory and lists what it stopped. When nothing of the app was running, it prints `Nothing of my-app was running.` and still succeeds, with `my-app` replaced by your app's name. Use it too when `prisma dev` was killed without a chance to stop the app. +`dev stop` stops the app in one environment and lists what it stopped. It finds the app as `prisma dev` does, from your entry file or `--name`, and stops the environment `dev` unless you pass `--environment`. When nothing of the app was running, it prints `Nothing of my-app was running.` and still succeeds, with `my-app` replaced by your app's name. Use it too when `prisma dev` was killed without a chance to stop the app. Stopping keeps the data and the ports, so the next `dev` is a warm start: same ports, same data. @@ -110,19 +111,28 @@ Stopping keeps the data and the ports, so the next `dev` is a warm start: same p The services, databases, and buckets `dev` runs belong to the directory you run it in. Two checkouts of the same app, such as two clones of its repository, run separate service processes on separate ports, with separate databases and separate buckets. A rebuild in one never restarts the other's services, and a row or an object written in one is not visible in the other. -A directory keeps the local state of every app you run from it. If you run a different app from the same directory (another entry file, or the same one under another name with `--name`), `dev` first stops the previous app's services and databases, keeps their data and ports, and says so: +A directory keeps the local state of every app you run from it. Running a different app from the same directory (another entry file, or the same one under another name with `--name`) stops nothing: both apps run at once, each on its own ports. -```text no-copy -[dev] stopped the local services of "shop", the app run here before; its data is kept +A stopped service or database keeps its port reserved, and a database keeps its data, even after you delete the checkout. There is no command to remove them yet. + +## Run a separate copy with `--environment` + +`prisma dev` runs as the environment `dev`. `--environment` names another, and each name is a complete, separate local copy of the app, with its own services, databases, buckets, and ports. Two environments of one app run at once in one directory, and starting one stops nothing. The common use is a clean copy for tests that leaves your working data alone: + +```npm +npx prisma dev # dev, with your working data +npx prisma dev --environment test --fresh --detach # a clean copy; dev is untouched +npx prisma dev url my-app.gateway --environment test # test's URL +npx prisma dev stop --environment test ``` -Running `shop` again with `prisma dev` resumes it. +Everything local to one copy lives in `.prisma-composer/dev//`. The `log` operation takes the same name as its `environment` option. -A stopped service or database keeps its port reserved, and a database keeps its data, even after you delete the checkout. There is no command to remove them yet. +Environment names are case-sensitive, but on a case-insensitive filesystem, such as the default on macOS, `Dev` and `dev` would share one folder. So the first `prisma dev` in an environment records its exact name, and `dev`, `dev url`, `dev stop`, and the `log` operation refuse a name that differs from it only in case, with `DEV.ENVIRONMENT_NAME_MISMATCH`. ## Start clean with `--fresh` -`--fresh` deletes this app's local services, databases, and buckets, with their data, before starting. The next start creates them again, empty, and gives the services the lowest free ports. Other apps run from the same directory keep theirs. Use it when your local data is disposable, which during development it usually is: +`--fresh` deletes this app's local services, databases, and buckets in this environment, with their data, before starting. The next start creates them again, empty, and gives the services the lowest free ports. Other apps and other environments run from the same directory keep theirs. Use it when your local data is disposable, which during development it usually is: ```npm npx prisma dev --fresh @@ -132,7 +142,7 @@ Run with `--fresh` too if `dev` fails after you upgrade Composer with an error s ## See everything on this machine -An emulator is the program on your machine that stands in for Prisma Compute, Prisma Postgres, or a bucket, and holds one instance for each service, database, or bucket that `dev` started. The emulators are shared by every directory on the machine. `emulator list` shows each emulator, whether it is running, and every instance it holds, with the address and directory it belongs to. It works from any directory: +An emulator is the program on your machine that stands in for Prisma Compute, Prisma Postgres, or a bucket, and holds one instance for each service, database, or bucket that `dev` started. The emulators are shared by every directory on the machine. `emulator list` shows each emulator, whether it is running, and every instance it holds, with the address, directory, and environment it belongs to. It works from any directory: ```npm npx prisma emulator list @@ -183,11 +193,35 @@ It follows live, like `tail -f`. It only reads the running app. It never builds, Everything above the cloud boundary is real: your actual service code, real databases you can migrate and query, real object storage, and the same wiring a deploy creates, including [service keys](/composer/services-and-contracts#calls-are-authenticated-for-you). What is swapped are the providers underneath: local emulators stand in for Prisma Compute and Prisma Postgres, so no token, workspace, or network is involved. Three consequences worth knowing: - **Direct RPC probes get `401` here too.** `dev` runs the deploy pipeline, so providers only accept their wired consumers, exactly as in production. Exercise a provider through a consumer, or in [tests](/composer/testing), where nothing is provisioned and every call passes through. -- **Unset secrets do not stop the app.** A secret you have not set in your shell gets a local placeholder and a one-line warning. The app boots and serves. Only the code path that actually uses that secret fails, at the real external service it calls. Set the secret in your shell to exercise that path. +- **Secrets come from your environment variables.** See [Secrets](#secrets) below. - **The emulators outlive a session.** They are shared, machine-wide programs, so your data survives `Ctrl-C` and even a reboot until you pass `--fresh`. That is what makes restarts warm. Windows is not supported yet; see [Limitations](/composer/limitations). +## Secrets + +`prisma dev` reads each secret your services bind with `envSecret` from the environment variables it runs with. It never makes a value up, and never reuses one from an earlier run. Export the secret in the shell you run `prisma dev` from, or keep it in a `.env` file and load that file from `prisma.config.ts`. To load it, install the `dotenv` package and make this the first line of `prisma.config.ts`: + +```npm +npm install dotenv +``` + +```ts title="prisma.config.ts" +import 'dotenv/config'; +``` + +`process.loadEnvFile('.env')` also works, but only when the CLI runs under Node, not Bun. + +If a secret that a service's input schema requires is unset or empty, `prisma dev` stops before it starts anything, and names the variable and the service. If the schema marks the secret optional, the service starts and sees that field as absent. Change a value and run `prisma dev` again, without `--fresh`, and the services that read it restart with the new value. Values bound with `envParam` come from the same place, and an unset one always stops `prisma dev`, naming it. + +Each service gets only the secrets and params its own input points at. Code that reads `process.env.X` directly, where `X` is bound by another service, gets nothing. + +A `.env` that only your framework loads, such as Next.js, does not count, because Composer reads each secret before the framework's dev server starts. + +:::warning +A `.env` loaded by `prisma.config.ts` is read by `prisma deploy` too. Deploy uploads any secret the target environment does not have yet from the environment variables it runs with, so a local-only value in `.env` becomes the hosted value. Keep local-only values out of `.env` before you deploy, or deploy from a shell where it is not loaded. +::: + ## Next steps - [Deploying](/composer/deploying): the same app, on Prisma Compute. diff --git a/apps/docs/content/docs/composer/porting-an-app.mdx b/apps/docs/content/docs/composer/porting-an-app.mdx index 24449f6823a..efc18908282 100644 --- a/apps/docs/content/docs/composer/porting-an-app.mdx +++ b/apps/docs/content/docs/composer/porting-an-app.mdx @@ -37,7 +37,7 @@ Add a `service.ts` with `compute({ name, deps, build: node({ module, entry }) }) Bun.serve({ port: service.port(), hostname: '0.0.0.0', fetch: handler }); ``` -2. **Replace every other `process.env` read.** Config and credentials become fields of the service's [input schema](/composer/service-input). Anything another service provides becomes a [dependency](/composer/services-and-contracts). If a value differs per stage (an app origin, an external URL), bind it with `envParam`. Bind a credential with `envSecret`. +2. **Replace every other `process.env` read.** Config and credentials become fields of the service's [input schema](/composer/service-input). Anything another service provides becomes a [dependency](/composer/services-and-contracts). If a value differs per environment (an app origin, an external URL), bind it with `envParam`. Bind a credential with `envSecret`. 3. **If it talks to Postgres**: declare `deps: { db: rawPostgres() }`, imported from `@prisma/composer-prisma-cloud`, and build your existing client (`pg`, Bun's `SQL`, whatever you use today) from the injected `db.url` instead of a connection-string env var. See [Databases](/composer/databases). @@ -96,7 +96,7 @@ Add `export const dynamic = 'force-dynamic'` to any page or server action that c ## More than one service -Port them into one `module.ts` and replace the URLs they used to reach each other with [contracts](/composer/services-and-contracts). The payoff is that the calls between services become typed, and every environment (production, stages, tests) gets the wiring for free. +Port them into one `module.ts` and replace the URLs they used to reach each other with [contracts](/composer/services-and-contracts). The payoff is that the calls between services become typed, and every environment (production, staging, tests) gets the wiring for free. ## Verify the port diff --git a/apps/docs/content/docs/composer/service-input.mdx b/apps/docs/content/docs/composer/service-input.mdx index f610dbc8867..9b3e34cf474 100644 --- a/apps/docs/content/docs/composer/service-input.mdx +++ b/apps/docs/content/docs/composer/service-input.mdx @@ -42,7 +42,7 @@ const chatInput = type({ stripeEnabled: 'false' }).or( ## Bind values at provision -The service declares what shapes are legal; the place that provisions it decides where each value comes from. The binding is a plain object mirroring the schema's shape, whose leaves are literals, `envParam(...)`, or `envSecret(...)`: +The service declares what shapes are legal; the place that provisions it decides where each value comes from. The binding is a plain object mirroring the schema's shape, whose leaves are literals, `envParam(...)`, `envSecret(...)`, or values from `resolve()` ([below](#values-that-differ-per-environment)): ```ts title="module.ts" import { envParam, envSecret } from '@prisma/composer-prisma-cloud'; @@ -50,7 +50,7 @@ import { envParam, envSecret } from '@prisma/composer-prisma-cloud'; provision(scheduler, { input: { jobs: [{ jobId: 'tick', every: '60s' }], // a literal - region: envParam('REGION'), // a per-stage platform variable + region: envParam('REGION'), // a platform variable per environment apiKey: envSecret('SCHEDULER_API_KEY'), // a credential: name only, never the value }, }); @@ -60,9 +60,9 @@ Secretness is enforced by validation, not annotation: binding a plain literal wh ### `envParam`: plain values the code cannot know -An app origin is the canonical case: it differs between production and every preview stage, and a stage's public URL does not exist until that stage first deploys. Each stage keeps its own copy of the variable, so one topology serves them all. +An app origin is the canonical case: it differs between production and every preview environment, and an environment's public URL does not exist until that environment first deploys. Each environment keeps its own copy of the variable, so one topology serves them all. -How the value travels: **the stage's platform variable is the store; the deploying shell only seeds it.** At deploy, preflight checks the name exists for the target stage, and a name the stage is missing is copied up from the deploying shell's environment. Once the stage has it, your shell no longer matters. To change the value later, set it on the platform and redeploy; a running instance's environment is frozen when the instance is created. +How the value travels: **the environment's platform variable is the store; the deploying shell only seeds it.** At deploy, preflight checks the name exists for the target environment, and a name the environment is missing is copied up from the deploying shell's environment. Once the environment has it, your shell no longer matters. To change the value later, set it on the platform and redeploy; a running instance's environment is frozen when the instance is created. `envParam` values arrive as raw strings, so bind them to string fields. @@ -77,6 +77,37 @@ if (input.stripeEnabled) stripe(input.stripeSecretKey.expose()); A reusable Module forwards a secret need to its parent without ever learning the platform name (see [Apps and Modules](/composer/apps-and-modules#reusable-modules)), which is what lets a Module require credentials without dictating your naming. +## Values that differ per environment + +The graph is the same in every environment: the same services, the same databases, the same wiring. What may differ is configuration. A module body computes it with `resolve()`, from the name of the environment being deployed: + +```ts title="module.ts" +import { module, resolve } from '@prisma/composer'; +import echoService from './echo.ts'; + +export default module('shop', ({ environment, provision }) => { + const greeting = resolve([environment.name], ([name]) => `hello from ${name}`); + provision(echoService, { input: { greeting } }); +}); +``` + +```npm +npx prisma deploy # greeting is "hello from production" +npx prisma deploy --environment staging # "hello from staging" +npx prisma dev # "hello from dev" +``` + +`environment.name` and the result of `resolve()` are **values**: stand-ins for data that is known only once the command knows which environment it runs. The module body cannot read a value, compare it, or branch on it. It can only pass it on: as a dependency of another `resolve()`, as a leaf of a service's input binding at any depth, or as a service param. A value cannot be a provision id or a `deps` entry, and a Module's `secrets` and `params` bindings take `envSecret` and `envParam` sources, not values. + +`resolve(dependencies, fn)` lists the values it depends on, and `fn` receives their real values as one tuple, in the same order. After every module body has run, the deploy runs each `fn` once, dependencies first, and puts the result where the value was bound. `fn` runs synchronously and returns plain data: strings, finite numbers, booleans, `null`, arrays, and plain objects. + +Two rules follow from running `fn` after the module bodies: + +- **`fn` cannot add to the graph.** Calling `provision()` inside `fn` fails the deploy. Provision the node in the module body and pass the value into it. +- **`fn` must depend only on its dependencies.** `deploy`, `dev`, and the `destroy` operation all run it, sometimes in more than one process, and each run must compute the same graph. A `fn` that reads the clock, a random number, a file, or an environment variable deploys a graph nobody checked. To retire an environment, keep its case in every `fn` until the `destroy` operation for it has finished. + +`deploy` and `dev` stop before anything changes when `fn` throws, returns `undefined` anywhere in its result, returns a value, `envParam()`, `envSecret()`, a Promise, a function, or a class instance, or when a value depends on itself. The message names the binding the value sits in, such as `input key "greeting" of service "shop.echo"`. Return a result for every environment: Composer never picks a default. + ## Absence is the schema's call An env-bound field whose variable is unset (or empty) resolves to *key omitted*. Whether that is legal is the schema's call: an optional field, a union arm, or a validation error that fails the deploy. A credential for an off-by-default feature is an ordinary optional `SecretString` field, not a framework flag. Because an omitted key can also be a typo'd variable name, the deploy report prints every key that resolved absent; check it when a value goes missing. @@ -103,5 +134,5 @@ At boot the framework swaps each pointer for a redacting box over the named vari ## Next steps -- [Deploying](/composer/deploying): how a fresh stage gets its variables in CI. +- [Deploying](/composer/deploying): how a fresh environment gets its variables in CI. - [Testing](/composer/testing): supply an input double under the reserved `input` key. diff --git a/apps/docs/content/docs/compute/branching.mdx b/apps/docs/content/docs/compute/branching.mdx index 3d3080086bf..a2019be34d5 100644 --- a/apps/docs/content/docs/compute/branching.mdx +++ b/apps/docs/content/docs/compute/branching.mdx @@ -36,7 +36,7 @@ With [deploy on push](/compute/deploy-on-push) set up, a staging environment is | **URL** | Generated, printed in the deploy report | Generated, printed in the deploy report | Generated; custom domains attach here only | | **Teardown** | Deleting the Git branch removes it | Deleting the Git branch removes it | Automated cleanup never touches it | -If the app reads `DATABASE_URL`, a preview or staging environment is only as separate as that value. Without GitHub, `npx prisma deploy --stage staging` creates a staging environment from your terminal or another CI system; see [Deploying](/composer/deploying#production-and-stages). +If the app reads `DATABASE_URL`, a preview or staging environment is only as separate as that value. Without GitHub, `npx prisma deploy --environment staging` creates a staging environment from your terminal or another CI system; see [Deploying](/composer/deploying#environments). ## How the CLI picks a branch @@ -65,7 +65,7 @@ Listing branches doesn't expand the services and databases inside them. Use the You rarely create branches by hand, because they are created automatically: - **From GitHub**: when a repo is connected, creating a Git branch creates the matching platform branch, and your repository's [deploy workflow](/compute/deploy-on-push) deploys each push to it as a preview. To set this up, see the [GitHub integration docs](/compute/github). -- **From the CLI**: commands that target a branch that doesn't exist yet, such as `service create --branch feature/search` or a [Composer stage deploy](/composer/deploying), create it. +- **From the CLI**: commands that target a branch that doesn't exist yet, such as `service create --branch feature/search` or a [Composer deploy to a new environment](/composer/deploying#environments), create it. Connecting GitHub doesn't create branches retroactively. It aligns your default branch with the repo's default branch and sets up automation for future events. diff --git a/apps/docs/content/docs/compute/deploy-on-push.mdx b/apps/docs/content/docs/compute/deploy-on-push.mdx index eaaac896e14..d780f68feb1 100644 --- a/apps/docs/content/docs/compute/deploy-on-push.mdx +++ b/apps/docs/content/docs/compute/deploy-on-push.mdx @@ -40,7 +40,7 @@ A Git branch you keep, such as `staging`, works as a staging environment. Every npx prisma project env add API_BASE_URL=https://staging-api.example.com --branch staging ``` -When a release is ready, merge `staging` into the default branch, and that push updates production. On Compute, the staging services cost money only while they do work, such as serving traffic, because creating a preview branch is free and an idle app scales to zero; see [Compute pricing](/compute/pricing#what-is-not-billed-separately). Without GitHub, `npx prisma deploy --stage staging` deploys the same kind of persistent staging environment from your terminal or another CI system, as [Deploying](/composer/deploying#production-and-stages) shows. +When a release is ready, merge `staging` into the default branch, and that push updates production. On Compute, the staging services cost money only while they do work, such as serving traffic, because creating a preview branch is free and an idle app scales to zero; see [Compute pricing](/compute/pricing#what-is-not-billed-separately). Without GitHub, `npx prisma deploy --environment staging` deploys the same kind of persistent staging environment from your terminal or another CI system, as [Deploying](/composer/deploying#environments) shows. ### Coming from Vercel or Netlify previews @@ -59,7 +59,7 @@ Have the assistant (Claude Code, Codex, Cursor or another coding agent) work on Push-to-deploy needs a repository connection and a deploy workflow, and you set up both: 1. **The repository connection.** [`git connect`](/cli/git) installs the Prisma GitHub App and registers the repository with your project. This lets workflow runs authenticate: a job exchanges its GitHub OIDC token for a Prisma workspace token that expires after 30 minutes, so the workflow needs no repository secrets. The connection also subscribes the project to branch events, which is what tears a preview down when its Git branch is deleted. -2. **The deploy workflow.** [prisma/cloud-deploy-action](https://github.com/prisma/cloud-deploy-action) runs in your repository's GitHub Actions. On each push it installs dependencies, runs your build, and runs the [`deploy` command](/cli/deploy) against production or a stage named after the branch. +2. **The deploy workflow.** [prisma/cloud-deploy-action](https://github.com/prisma/cloud-deploy-action) runs in your repository's GitHub Actions. On each push it installs dependencies, runs your build, and runs the [`deploy` command](/cli/deploy) to `production`, or to an environment named after the branch. Connecting a repository does not deploy it; deploys come from the workflow. Without the connection, the workflow has no credential: the action prints a notice, sets its `outcome` output to `skipped-no-credential`, and exits successfully, so the run stays green. @@ -163,7 +163,7 @@ git switch -c feature/search git push -u origin feature/search ``` -The action deploys the branch as a [stage](/composer/deploying#production-and-stages) named after it, which is a [preview branch](/compute/branching) of the same project. The preview has its own services, a new database for each database your module declares, its own buckets, and its own URL. A database, API or other service the app reaches through an environment variable such as `DATABASE_URL` is only as separate as that variable's preview-scoped value. Confirm it from your terminal: +The action deploys the branch as an [environment](/composer/deploying#environments) named after it, which is a [preview branch](/compute/branching) of the same project. The preview has its own services, a new database for each database your module declares, its own buckets, and its own URL. A database, API or other service the app reaches through an environment variable such as `DATABASE_URL` is only as separate as that variable's preview-scoped value. Confirm it from your terminal: ```npm npx prisma service list --branch feature/search @@ -185,4 +185,4 @@ The platform tears down the matching preview: its services, databases, and bucke - [GitHub integration](/compute/github): what the repository connection is and does. - [Environments: production, staging and preview branches](/compute/branching): how preview branches relate to Git branches. -- [Deploying](/composer/deploying): stages, deploy state, and per-stage secrets, which apply to CI deploys too. +- [Deploying](/composer/deploying): environments, deploy state, and secrets per environment, which apply to CI deploys too. diff --git a/apps/docs/content/docs/compute/faq.mdx b/apps/docs/content/docs/compute/faq.mdx index 2a262d8cd49..d047be37b23 100644 --- a/apps/docs/content/docs/compute/faq.mdx +++ b/apps/docs/content/docs/compute/faq.mdx @@ -22,7 +22,7 @@ Compute is built for apps whose server code is TypeScript and whose database is ## What it does well - One deploy for the app and its database. With [Prisma Composer](/composer) you describe each service and the databases it depends on in TypeScript; `npx prisma dev` runs it on your laptop, and `npx prisma deploy` provisions the services on Compute, the databases on Prisma Postgres and the authenticated connections between them. -- A preview per non-default branch. Once [deploy on push](/compute/deploy-on-push) is set up, a push to any non-default branch deploys a stage named after it, with its own services and URL and, for databases declared in the Composer module, its own new database; production data is not copied, and deleting the branch tears it down. A branch you keep, such as `staging`, is a long-lived staging environment. +- A preview per non-default branch. Once [deploy on push](/compute/deploy-on-push) is set up, a push to any non-default branch deploys an environment named after it, with its own services and URL and, for databases declared in the Composer module, its own new database; production data is not copied, and deleting the branch tears it down. A branch you keep, such as `staging`, is a long-lived staging environment. - Memory-preserving scale-to-zero. Idle instances suspend with a memory snapshot, stop incurring Compute charges, and resume in milliseconds with memory intact. Deployments and preview branch creation are not billed on their own. See [Pricing](/compute/pricing) for billing and [Keeping instances awake](/compute/keeping-instances-awake) for bounded background work. - Standard Postgres underneath. Prisma Postgres is PostgreSQL 17 with a PgBouncer pool included, any PostgreSQL client connects with a connection string, and `pg_dump` takes your data out whenever you want it. - Streaming and background work inside the limits. Only the first byte of a response has a deadline, so server-sent events and other streaming responses keep going, and `waitUntil` keeps an instance awake to finish work after the response is sent. diff --git a/apps/docs/content/docs/guides/authentication/clerk/nextjs.mdx b/apps/docs/content/docs/guides/authentication/clerk/nextjs.mdx index d91012fa714..2e34294a567 100644 --- a/apps/docs/content/docs/guides/authentication/clerk/nextjs.mdx +++ b/apps/docs/content/docs/guides/authentication/clerk/nextjs.mdx @@ -497,7 +497,7 @@ Link the directory to the project the deploy created: npx prisma project link clerk-nextjs-prisma ``` -Then add both secrets to the production role, which is the scope a deploy without `--stage` targets (the one you just ran). Read each value into your shell with `read -rs`, which neither echoes it nor records it in your shell history: paste the secret key at the first prompt and the live endpoint's signing secret at the second, pressing Enter after each. When you pass only the variable name, the CLI reads the value from your shell environment. The values are stored encrypted and are never shown again, so keep your own copy: +Then add both secrets to the production role, which is the scope a deploy without `--environment` targets (the one you just ran). Read each value into your shell with `read -rs`, which neither echoes it nor records it in your shell history: paste the secret key at the first prompt and the live endpoint's signing secret at the second, pressing Enter after each. When you pass only the variable name, the CLI reads the value from your shell environment. The values are stored encrypted and are never shown again, so keep your own copy: ```bash read -rs CLERK_SECRET_KEY && read -rs CLERK_WEBHOOK_SIGNING_SECRET && export CLERK_SECRET_KEY CLERK_WEBHOOK_SIGNING_SECRET diff --git a/apps/docs/content/docs/guides/frameworks/solid-start.mdx b/apps/docs/content/docs/guides/frameworks/solid-start.mdx index fb3ea55720c..5be8fe328ab 100644 --- a/apps/docs/content/docs/guides/frameworks/solid-start.mdx +++ b/apps/docs/content/docs/guides/frameworks/solid-start.mdx @@ -399,8 +399,8 @@ check: enabled Skill Package Version Installed into prisma-8 @prisma/orm-postgres 8.0.0-rc.21 .claude/skills, .cursor/skills, .agents/skills, .devin/skills -prisma-composer-core-concepts @prisma/composer 0.29.1 .claude/skills, .cursor/skills, .agents/skills, .devin/skills -prisma-platform-core-concepts prisma 8.0.0-rc.28 .claude/skills, .cursor/skills, .agents/skills, .devin/skills +prisma-composer-core-concepts @prisma/composer 0.36.0 .claude/skills, .cursor/skills, .agents/skills, .devin/skills +prisma-platform-core-concepts prisma 8.0.0-rc.30 .claude/skills, .cursor/skills, .agents/skills, .devin/skills ⚠ [INIT.CONFIG_KEPT] prisma.config.ts already exists, so init left it alone instead of writing the skills section. → Add skills: { agents: ["claude", "cursor", "agents", "devin"] } to the object passed to definePrismaConfig in prisma.config.ts. diff --git a/apps/docs/content/docs/guides/upgrade-prisma-orm/postgresql.mdx b/apps/docs/content/docs/guides/upgrade-prisma-orm/postgresql.mdx index 3a803420170..b8197b7773c 100644 --- a/apps/docs/content/docs/guides/upgrade-prisma-orm/postgresql.mdx +++ b/apps/docs/content/docs/guides/upgrade-prisma-orm/postgresql.mdx @@ -228,7 +228,7 @@ After this install, `npx prisma ` runs the Prisma ORM 8 CLI and `npx pr npx prisma --version ``` -**Expected result:** the command prints `8.0.0-rc.28` or a newer version. That number does not match the version of `@prisma/orm-postgres`, because the CLI is released separately. +**Expected result:** the command prints `8.0.0-rc.30` or a newer version. That number does not match the version of `@prisma/orm-postgres`, because the CLI is released separately. ### 2.2. Create the Prisma ORM 8 config diff --git a/apps/docs/content/docs/orm/release-status.mdx b/apps/docs/content/docs/orm/release-status.mdx index 1397fd462aa..ec345355016 100644 --- a/apps/docs/content/docs/orm/release-status.mdx +++ b/apps/docs/content/docs/orm/release-status.mdx @@ -39,9 +39,9 @@ For MongoDB the library is `@prisma/orm-mongo`. [Supported databases](/orm/suppo The two packages have different version numbers, and that is normal: they are released separately, and the command-line tool gets more frequent releases. Install both at `latest`; any two `latest` versions work together, and you do not pair the numbers yourself. -| Package | `latest` on 28 October 2026 | +| Package | `latest` on 30 October 2026 | | --- | --- | -| `prisma` (the command-line tool) | `8.0.0-rc.28` | +| `prisma` (the command-line tool) | `8.0.0-rc.30` | | `@prisma/orm-postgres` (the library) | `8.0.0-rc.21` | | `@prisma/orm-mongo` (the MongoDB library) | `8.0.0-rc.21` | diff --git a/apps/docs/content/docs/orm/supported-versions.mdx b/apps/docs/content/docs/orm/supported-versions.mdx index 61514fd2bd2..3a211d307f4 100644 --- a/apps/docs/content/docs/orm/supported-versions.mdx +++ b/apps/docs/content/docs/orm/supported-versions.mdx @@ -62,4 +62,4 @@ psql "$DATABASE_URL" -c "SELECT version();" `psql --version` on its own prints the version of the `psql` program, not the server. For MongoDB, run `db.version()` in `mongosh`. For Bun or Deno, run `bun --version` or `deno --version`. -`prisma` is the command-line tool, installed as a dev dependency beside the library, and the two are versioned separately. The versions on this page were checked on 22 October 2026, against the releases before `prisma` 8.0.0-rc.28 and the 8.0.0-rc.21 libraries. +`prisma` is the command-line tool, installed as a dev dependency beside the library, and the two are versioned separately. The versions on this page were checked on 22 October 2026, against the `prisma` releases before 8.0.0-rc.28 and the 8.0.0-rc.21 libraries.