diff --git a/apps/site/content/changelog/2026-10-09.mdx b/apps/site/content/changelog/2026-10-09.mdx new file mode 100644 index 00000000000..055b334d02d --- /dev/null +++ b/apps/site/content/changelog/2026-10-09.mdx @@ -0,0 +1,183 @@ +--- +title: "Prisma ORM 8 migrations now ask before they drop your data" +date: "2026-10-09" +version: "2026-10-09" +slug: "2026-10-09" +headline: "Prisma ORM 8 migrations now ask before they drop your data" +tags: + - "Prisma" + - "Prisma ORM" + - "Prisma Compute" + - "Prisma Postgres" +canonical: "/changelog#log2026-10-09" +metaDescription: "Prisma ORM 8 migrations now ask about each model or field they would drop, and --rename keeps the rows. Also new: runtime logs in the Prisma Console, a comparison of a preview branch with production, and Prisma Composer's settings move into prisma.config.ts." +share: + active: true + content: "Look at this page: " +--- +**Prisma ORM 8 migrations now ask about each model or field they would drop, and you can answer with a rename that keeps the rows.** In the Prisma Console, a Prisma Compute deployment now shows its runtime logs, and a preview branch's services and connections can be compared with production. Prisma Composer, the TypeScript description of a Prisma Compute app's services and databases, now reads its settings from the `composer` section of `prisma.config.ts`, so a project has one config file, and the old separate file needs to be moved. + +Two deadlines from earlier entries still stand: Prisma Postgres Early Access databases are deleted on **November 1, 2026**, and Accelerate is retired on **December 1, 2026**. The steps are under "What you need to do" below. + +## Keep your data when a migration would drop it + +When your schema removes a model or a field, `prisma migration plan` and `prisma db update` now stop and ask whether each one is a real delete or a rename, before they write anything. Before, a renamed field was planned as a drop and a create, the `--confirm` flag accepted every such change at once, and the rows were gone after the migration. Now, at your terminal, the command prompts you for each question, and you can also answer up front with flags: `--delete Legacy` for a model or `--delete User.nickname` for a field lets the data go, and the new `--rename User.name:User.fullName` keeps it. A rename keeps the table or column and its rows instead of dropping and recreating it. ([#30648](https://github.com/prisma/orm/pull/30648), [#30638](https://github.com/prisma/orm/pull/30638)) + +```bash title="Terminal" +npx prisma migration plan --rename User.name:User.fullName --delete Legacy +``` + +In CI, where nobody can answer, a command with an open question fails with `CLI.CONSENT_REQUIRED` and lists the flags to add, so a schema change that drops data fails once and you add the flag to the job. `prisma db update` also stops and asks when a change lets more people read or write a model's rows, for example when it drops a row-level security policy, and you accept that with `--allow `. Dropping an index, a constraint, a check, or a default no longer asks, because no data is lost. On MongoDB, renames are refused for now. The [migration plan](https://www.prisma.io/docs/cli/migration-plan#renames-and-data-loss) reference lists each question and its answer. + +Prisma ORM 8 is still a release candidate. You need two packages for it, released separately and with different version numbers: the library your app imports, `@prisma/orm-postgres`, which replaces `@prisma/client` and is at `8.0.0-rc.17` for this change, and the command-line tool, `prisma`, at `8.0.0-rc.22`. `prisma@latest` installs the Prisma 8 tool, and `prisma@7`, which `prisma@prev` also points at, is Prisma ORM 7. The tool also runs Prisma Compute deploys for every app, including Prisma ORM 7 apps. + +Two Prisma ORM 8 words appear throughout this entry. The contract is a generated file that describes your schema, written by `prisma contract emit` and read by the client and the migration commands, much as `prisma generate` wrote the client in Prisma ORM 7; "re-emit" means running that command again. Signing a database with `prisma db sign --db "$DATABASE_URL"` marks it as already matching the contract, so no migration runs against it. + +
+ Read the migration plan reference + See the rc.17 release notes +
+ +## Read runtime logs and compare branches in the Console + +A deployment's page in the [Prisma Console](https://console.prisma.io) now shows the output your app writes while it runs, and it updates on its own. You can pause the stream, refresh it, copy it, and jump to the latest line. Before, the page showed the deployment's status, ports, and environment variables, and the logs were only available from the command line with `prisma service logs`. The **Serving live** card on the app page has a **View runtime logs** button that opens the live deployment's logs directly. + +The **Topology** view, which draws a project's services and databases and how they connect, now opens a preview branch with a comparison against production. {/* plain-language:defined */} Services, ports, and connections that the branch adds or removes are highlighted, unchanged parts fade, and a changed value shows its before and after. A toggle turns the comparison off and shows the branch on its own. + +Your app also receives two headers on every request it serves. `Prisma-Connecting-IP` holds the address of the client that made the request, as a single value, and `Prisma-Request-ID` holds an id for the request that Prisma also returns on the response, so you can match a log line to a request. Any `Prisma-*` header a client sends is dropped before the request reaches your app, so your code can trust these two. + +
+ Open the Console + Read about deployments +
+ +## Share query logic across models and lock the rows you read + +Prisma ORM 8 can now define a piece of a query once and apply it to any model that has the right fields. A soft-delete filter, a default sort, or a set of fields to select becomes a function you pass to a collection. In `8.0.0-rc.15` this was called a scope, and `8.0.0-rc.17` renamed it: you build the piece with `db.orm.fragment(...)` or `db.orm.public.Post.fragment(...)`, and apply it with `.with(...)`. If you subclass a model's collection to add methods such as `published()`, those methods now survive `where`, `orderBy`, and `limit`, so `db.orm.public.Post.where({ userId }).published()` compiles. ([#30564](https://github.com/prisma/orm/pull/30564), [#30560](https://github.com/prisma/orm/pull/30560), [#30635](https://github.com/prisma/orm/pull/30635)) + +```ts title="src/posts.ts" +const notDeleted = db.orm.public.Post.fragment((posts) => + posts.where((p) => p.deletedAt.isNull()), +); + +const posts = await db.orm.public.Post.with(notDeleted).orderBy((p) => p.createdAt.desc()).all(); +``` + +The [query fragments](https://www.prisma.io/docs/orm/reference/orm-client#query-fragments) reference has two more examples: a soft-delete filter that works on any model with a `deletedAt` field, and a helper that turns a `?sort=` value from a request into a safe `orderBy`. + +A read can also lock the rows it returns, so two workers that pick a job from a queue do not pick the same one: `db.orm.public.Job.where((j) => j.state.eq("queued")).forUpdate({ skipLocked: true }).first()`. Here `db.orm.public.Job` is the `Job` model in the `public` PostgreSQL schema. The ORM collections and the lower-level SQL query builder, `db.sql`, both have `forUpdate()`, `forNoKeyUpdate()`, `forShare()`, and `forKeyShare()`, each with `nowait` and `skipLocked` options. They exist only on databases that support them, so they are absent on SQLite. ([#30549](https://github.com/prisma/orm/pull/30549), [#30555](https://github.com/prisma/orm/pull/30555)) + +The release candidates of this week also add the following: + +- **Invalidate cached reads.** The built-in cache middleware, which keeps query results in your app's memory, can now drop an entry on demand: `cache.invalidate({ keys: ["posts:home"] })` removes the reads that named that key in `cacheAnnotation({ key })`. The default store keeps an entry for 60 seconds. ([docs](https://www.prisma.io/docs/orm/middleware/built-in-cache), [#30530](https://github.com/prisma/orm/pull/30530)) +- **Run code after a transaction commits.** Middleware has an `afterTransaction` hook that runs for each query once the transaction it ran in has committed or rolled back, and tells you whether it was committed, rolled back, or unknown. ([#30614](https://github.com/prisma/orm/pull/30614)) +- **Rename a table in a hand-written migration.** `this.renameTable({ table: "userProfile", to: "UserProfile" })` in a migration made with `prisma migration new` renames the table and the constraints and indexes named after it, and keeps the rows. ([docs](https://www.prisma.io/docs/orm/reference/migration-api), [#30331](https://github.com/prisma/orm/pull/30331)) +- **Allow `null` inside a list.** `String?[]` allows `null` elements, `String[]?` allows a `null` list, and `String?[]?` allows both. ([#30051](https://github.com/prisma/orm/pull/30051)) +- **Give an existing integer column an `autoincrement()` default.** The migration now plans a sequence that starts past the column's current maximum, where it used to plan nothing. ([#30606](https://github.com/prisma/orm/pull/30606)) +- **Name the index that backs a relation.** `@relation(..., index: "post_author_live")` tells Prisma ORM 8 which index, unique constraint, or primary key serves the foreign key, so it creates no extra one. `prisma contract emit` now warns when two named indexes are identical or when a plain index repeats a unique constraint. ([#30561](https://github.com/prisma/orm/pull/30561)) +- **Hover, go to definition, and find references in your editor.** Hovering a model, field, or attribute in a `.prisma` file shows its declaration and documentation, and go to definition and find references work across every schema file of the project. The editor also completes the values inside a block such as `policy_select`. ([#30569](https://github.com/prisma/orm/pull/30569), [#30578](https://github.com/prisma/orm/pull/30578), [#30567](https://github.com/prisma/orm/pull/30567)) +- **Read more Prisma 6 MongoDB schemas.** `prisma orm init` recognizes a Prisma 6 MongoDB project, and the reader accepts every native type Prisma 6 accepts except `DateTime @db.Timestamp`. ([#30521](https://github.com/prisma/orm/pull/30521)) + +## What you need to do + +- **If you deploy to Prisma Compute, move Composer's settings into `prisma.config.ts` before your next deploy with `prisma@8.0.0-rc.20` or newer.** If the Console set up deploys for your repository before October 8, its pull request wrote a `prisma-composer.config.mjs` file, and that file is no longer read; `prisma deploy` and `prisma dev` stop and tell you what to move. Move the `extensions` and `state` from the old file into a `composer` section, and delete the old file: ([composer#328](https://github.com/prisma/composer/pull/328)) + + ```ts title="prisma.config.ts" + import { definePrismaConfig } from "prisma/config"; + import { defineConfig as composer } from "@prisma/composer/config"; + import { nodeBuild } from "@prisma/composer/node/control"; + import { prismaCloud, prismaState } from "@prisma/composer-prisma-cloud/control"; + + export default definePrismaConfig({ + composer: composer({ + extensions: [prismaCloud(), nodeBuild()], + state: prismaState(), + }), + }); + ``` + +- **If a deploy with `prisma@8.0.0-rc.22` or newer fails because a package your service imports cannot be found**, add `dependencies: "external"` to that service, as in `node({ dir: "build", entry: "server.mjs", dependencies: "external" })`. A deploy of a `node({ dir, entry })` service now uploads only your build output, which is right for a build that bundles its packages. With `"external"`, the deploy also uploads the packages your build imports from `node_modules`, as that form did before. ([composer#341](https://github.com/prisma/composer/pull/341)) +- **If you are on a Prisma ORM 8 release candidate older than `8.0.0-rc.15`**, download `data-type-in-contract.ts` from the [rc.15 upgrade guide](https://github.com/prisma/orm/blob/v8.0.0-rc.15/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.14-to-8.0.0-rc.15/), run it with Node in your project root before any other step, then run `prisma db sign` against every database, as the breaking change about the contract file format below explains. Then replace each `--confirm` in your scripts, as described above. +- **If you are on Prisma ORM 7**, your code does not change. Check any script or CI job that installs `prisma@latest` and change it to `prisma@7`, because `latest` is Prisma ORM 8. The two deadlines below may apply to you. +- **Prisma Postgres Early Access databases are deleted on November 1, 2026 at 00:00 UTC.** The Console shows a notice on each affected project and database. The [migration guide](https://www.prisma.io/docs/postgres/migrate-from-ea-to-ga) walks you through the export and the restore. +- **Accelerate is retired on December 1, 2026.** If your app connects through a URL that starts with `prisma+postgres://accelerate.prisma-data.net`, [switch to a pooled connection or to the serverless driver](https://www.prisma.io/docs/postgres/database/switch-from-accelerate) before then. If you use Accelerate with your own database, [keep your database and connect to it without Accelerate](https://www.prisma.io/docs/accelerate/keep-your-database). + +## Breaking changes between Prisma ORM 8 release candidates + +These apply only if you already use a Prisma ORM 8 release candidate and are upgrading to `8.0.0-rc.15`, `8.0.0-rc.16`, or `8.0.0-rc.17`. If you are trying Prisma ORM 8 for the first time, you start on the newest release candidate and can skip this list, and if you are on Prisma ORM 7, nothing here changes your app: the bullets that mention a Prisma 7 schema are about Prisma ORM 8 reading that file. Several bullets end with `prisma contract emit` and `prisma db sign`; one run of each after all the other steps is enough. The release notes for [rc.15](https://github.com/prisma/orm/releases/tag/v8.0.0-rc.15), [rc.16](https://github.com/prisma/orm/releases/tag/v8.0.0-rc.16), and [rc.17](https://github.com/prisma/orm/releases/tag/v8.0.0-rc.17) list every change, including the ones that only affect extension authors, and each links an upgrade guide with scripts. + +- **`--confirm` no longer consents to data loss.** `prisma migration plan` and `prisma db update` ask about each model, field, or table they would lose data from, and you answer with `--delete` or `--rename`, as described above. Replace each `--confirm` in scripts and CI. ([#30648](https://github.com/prisma/orm/pull/30648)) +- **The contract file format changed, and a contract in the old format is refused with `CONTRACT.VALIDATION_FAILED` until you run the upgrade script.** Upgrade the extensions you use, such as pgvector and PostGIS, in the same step. Then download `data-type-in-contract.ts` from the rc.15 upgrade guide, run `node data-type-in-contract.ts` in your project root, which rewrites every contract and migration in your project, and run `prisma db sign` against every database. Until a database is signed, `prisma db migrate` refuses with `MIGRATION.MARKER_MISMATCH`. ([#30576](https://github.com/prisma/orm/pull/30576), [#30051](https://github.com/prisma/orm/pull/30051)) +- **`scope` is now `fragment`, and `apply` is now `with`.** The types `Scope`, `FieldScope`, and `ScopeFacts` are now `Fragment`, `FieldFragment`, and `FragmentFacts`. This applies to the SQL client only. ([#30635](https://github.com/prisma/orm/pull/30635), [#30647](https://github.com/prisma/orm/pull/30647)) +- **A bulk write refuses a `limit`, `offset`, `cursor`, or `distinct` it would ignore.** `updateAll`, `updateAndCount`, `deleteAll`, and `deleteAndCount` change every row that matches the filter. Before, `where(...).limit(10).deleteAll()` deleted every matching row. It now throws `ORM.ARGUMENT_INVALID`. Select the ids first, then delete by id. If your code applies a `where` only on some code paths, TypeScript now rejects `deleteAll()` and `updateAll()` on the result. ([#30564](https://github.com/prisma/orm/pull/30564), [#30560](https://github.com/prisma/orm/pull/30560)) +- **`variant()` takes the stored value, not the model name.** This applies only to schemas that use `@@base`, Prisma ORM 8's way to store several model variants in one table. For a variant declared with `@@base(Task, "bug")`, write `db.orm.public.Task.variant("bug")`. A value the schema does not declare now throws instead of silently reading every variant. ([#30577](https://github.com/prisma/orm/pull/30577)) +- **The `pg.sql` and `sqlite.sql` tags are removed.** Write ``@default(sql`now()`)``. The stored default does not change. ([#30534](https://github.com/prisma/orm/pull/30534)) +- **A Prisma 7 schema's date and time columns are read as text.** This is about Prisma ORM 8 reading your Prisma 7 file, not about Prisma ORM 7 itself. A `DateTime` column and the `@db.Timestamp`, `@db.Timestamptz`, `@db.Date`, and `@db.Time` columns now give you strings such as `"2026-09-14 10:00:00.123"` instead of `Temporal` values, so your app no longer needs a `Temporal` polyfill. Change the code that treated these fields as `Temporal` values, re-emit the contract, then run `prisma db sign`. ([#30553](https://github.com/prisma/orm/pull/30553)) +- **The cache middleware's store decides how long an entry lives.** `cacheAnnotation` no longer takes `ttl`, every annotated read is cached, `skip` is now `bypass`, and `maxEntries` moves from `createCacheMiddleware` to `createInMemoryCacheStore`. ([#30530](https://github.com/prisma/orm/pull/30530)) +- **`db.enums`, the list of each enum's members, now gives you each member as the database stores it.** A member stored as a bigint is a `bigint`, a date member is a `Date` or a `Temporal` value. Remove the conversions your code applied, and run `prisma contract emit`. An enum member must also be written as the database stores it, so `"01.5"` on a `numeric` enum is refused with a message that says what to write. ([#30628](https://github.com/prisma/orm/pull/30628)) +- **Every contract with a foreign key changes.** Run `prisma contract emit`, then `prisma migration plan`, which tells you what to do: write an empty migration with `prisma migration new` if you deploy with migrations, or run `prisma db sign` if you keep your database in sync with `db update`. A partial index no longer counts as the index behind a relation, so `migration plan` creates a plain one next to it unless the relation names the index with `index:`, and an index with a non-default `type` or `options` stops backing a relation in the same way. An unnamed `@@index` on exactly the columns of a unique constraint or primary key is left out of the contract, so `migration plan` drops it unless you give it a `name`. ([#30561](https://github.com/prisma/orm/pull/30561)) +- **If Prisma ORM 8 reads your Prisma 7 `schema.prisma`, the contract now records the constraint names Prisma 7 chose.** Run `prisma contract emit`, then `prisma db sign`, or `prisma migration plan` if Prisma ORM 8 already manages your migrations. ([#30606](https://github.com/prisma/orm/pull/30606)) +- **MongoDB indexes write their sort direction as `sort(field, Desc)`.** `@@index([createdAt(sort: Desc)])` is now `@@index([sort(createdAt, Desc)])`. The database index does not change. ([#30636](https://github.com/prisma/orm/pull/30636)) +- **A schema written in TypeScript must list the extensions whose types it uses.** A schema that uses a pgvector, PostGIS, or arktype-json column without listing that extension in `extensions` fails with `CONTRACT.CODEC_DESCRIPTOR_MISSING`. ([#30547](https://github.com/prisma/orm/pull/30547)) +- **`db verify --strict` reports a table that no contract declares as `CONTRACT.SCHEMA_VERIFICATION_FAILED`.** `CONTRACT.MARKER_REQUIRED` now only means the database has not been signed. If a script looks for the old code to detect stray tables, change it to the new one. ([#30601](https://github.com/prisma/orm/pull/30601)) + +## Prisma Compute + +A deploy now applies a database's migrations before the service that uses it goes live. Before, the two steps ran at the same time, so new code could serve requests for a few minutes against a database that was not yet at the new schema. A failed migration now stops the new code from shipping. ([composer#334](https://github.com/prisma/composer/pull/334)) + +`prisma deploy` also reports each step as it starts and finishes, with how long it took: loading the app, assembling each service, connecting to the project, checking environment variables, and applying the plan. The last line names the real total, as in `Deployed shop to production in 9m 35s`, where it used to show only the time the final apply took. ([composer#338](https://github.com/prisma/composer/pull/338)) + +In pnpm projects, `prisma dev` and `prisma deploy` no longer fail with `DEPLOY.ALCHEMY_BIN_MISSING`. ([composer#332](https://github.com/prisma/composer/pull/332)) + +Deleting a project now also stops the Compute apps it was running, within an hour, and the delete dialog says so. Before, the apps' servers kept running after the project was gone. + +## Prisma Postgres + +A Free workspace that has used up its included queries can now restore database access for 24 hours from the notice in the Console, once per workspace, so you can export your data or finish a task without opening a support request. The button is not offered while a payment, spend-limit, or support hold is active, and paid plans do not need it. The [Prisma Postgres FAQ](https://www.prisma.io/docs/postgres/faq#what-happens-if-i-exceed-the-included-queries-on-the-free-tier) describes each option when you reach the limit. + +## Prisma Console + +The sign-in page at `auth.prisma.io`, which the Prisma CLI and the Prisma MCP server send you to, now looks like the Console's own login page and follows your light or dark theme. When an OAuth sign-in fails, the error is now shown on the page. Before, it was sent to a notification that never appeared, so a failed sign-in looked like nothing had happened. + +## Docs and website + +- The [app templates page](/apps) is now a gallery. Each Prisma Compute template shows a screenshot of the running app, and you can filter by type and framework and sort by featured, newest, or popular. The filters live in the URL, so a link such as `/apps?framework=nextjs` opens the list already narrowed. +- The [changelog](/changelog) has a product filter, so you can see only the entries that cover Prisma Studio, Prisma Compute, Prisma Postgres, Prisma ORM, or the platform. +- The docs remember which database you pick in code examples across pages and reloads, and a link with `?db=postgresql` opens a page on that database's examples. +- [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push) now explains how to run a test version of your app next to production: every branch you push gets its own deployment, URL, and databases, a branch you keep gives you a staging environment, and only the default branch deploys production. +- [Import an existing database](https://www.prisma.io/docs/postgres/import-from-existing-database) is now a short guide: create the database, `pg_dump`, `pg_restore`, then verify. + +## Fixes + +### Prisma Compute + +- The pull request that Prisma opens to set up deploys on a connected repository works again. Before, a version conflict could stop it from being opened at all. The workflow it writes now sets a pnpm version for repositories without a `packageManager` field, and no longer has a job that tears down a deleted branch, because Prisma removes a deleted branch's deployments itself. A repository set up earlier keeps that failing job until you delete it from the workflow file. +- Projects that deploy through `prisma/cloud-deploy-action` set up by hand no longer show a **Builds paused** card forever. It clears once a CI build has succeeded. +- Leaving an app page open in the Console no longer ends in a `Failed to fetch` error screen after a dropped request, such as after your laptop sleeps. The page also polls less often while nothing is building. +- When a background refresh of the dashboard or a project overview fails, the Console keeps the page instead of replacing it with an error. + +### Prisma MCP server + +- Connecting Codex to the Prisma MCP server no longer returns `401` right after a successful Prisma sign-in. + +### Prisma ORM 8 + +- With Bun, `prisma orm init` and `prisma contract emit` no longer fail with `CONTRACT.VALIDATION_FAILED` on a valid contract. ([#30632](https://github.com/prisma/orm/pull/30632)) +- A `jsonb` column that holds a JSON string such as `"standard"` reads back as that string. Before, it failed with `RUNTIME.DECODE_FAILED`, and `"123"` read as a number. ([#30597](https://github.com/prisma/orm/pull/30597)) +- A query sent after `close()` fails with `DRIVER.NOT_CONNECTED`, and work already started finishes, instead of a misleading error or an unhandled rejection. ([#30533](https://github.com/prisma/orm/pull/30533)) +- A `Bytes` literal default or a pgvector list default no longer rolls back `db init`, `db update`, and `db migrate` with `MIGRATION.SCHEMA_VERIFY_FAILED`. ([#30603](https://github.com/prisma/orm/pull/30603)) +- On SQLite, a `now()` default stores the same text the application writes, so rows that took the default compare and sort correctly. ([#30612](https://github.com/prisma/orm/pull/30612)) +- When a contract change needs no database change, `prisma migration plan` explains why and names the command to run next. ([#30639](https://github.com/prisma/orm/pull/30639)) +- Dropping a constraint of a table with a long name no longer fails. ([#30606](https://github.com/prisma/orm/pull/30606)) +- Error messages from the database driver no longer include the connection string. ([#30451](https://github.com/prisma/orm/pull/30451)) +- A `@default` that the schema refuses is reported at the written value, with a message that says what to write instead, such as `Expected a number; got a list`. ([#30539](https://github.com/prisma/orm/pull/30539)) +- An unknown or misspelled type name reports one diagnostic, `PSL_UNRESOLVED_REFERENCE`, in both the SQL and MongoDB schema families. ([#30563](https://github.com/prisma/orm/pull/30563)) +- On MongoDB, a nullable list field accepts an explicit `null`, and the ORM accepts writes of enum values whose stored form differs from the value, such as bigint and date members. ([#30568](https://github.com/prisma/orm/pull/30568), [#30628](https://github.com/prisma/orm/pull/30628)) + +## Guides and articles + +- [App hosting platforms with managed Postgres compared (2026)](https://www.prisma.io/blog/app-hosting-platforms-with-managed-postgres-2026): Prisma Compute, Railway, Render, Fly.io, Supabase, Neon, and Vercel compared for an app next to a managed Postgres database, on previews, idle cost, pooling, backups, and price. + +--- + +*Need help applying these changes in production? [Prisma Enterprise Support](/enterprise) can help with schema design, performance, security, and compliance.* diff --git a/apps/site/content/changelog/2026-10-16.mdx b/apps/site/content/changelog/2026-10-16.mdx new file mode 100644 index 00000000000..9867c120ac5 --- /dev/null +++ b/apps/site/content/changelog/2026-10-16.mdx @@ -0,0 +1,180 @@ +--- +title: "Upgrade to a paid Prisma plan and it now renews on the day you upgraded" +date: "2026-10-16" +version: "2026-10-16" +slug: "2026-10-16" +headline: "Upgrade to a paid Prisma plan and it now renews on the day you upgraded" +tags: + - "Prisma" + - "Prisma Studio" + - "Prisma Compute" + - "Prisma Postgres" + - "Prisma ORM" + - "REST API" +canonical: "/changelog#log2026-10-16" +metaDescription: "A new paid Prisma plan now renews on the day of the month you upgraded, and the Console shows usage by billing period. Also new: service tokens scoped to one project with an expiry, mixins and weighted full-text search in Prisma ORM 8, and a Prisma Studio release." +share: + active: true + content: "Look at this page: " +--- +**A workspace that upgrades to a paid Prisma plan now renews on the day of the month it upgraded, and the Console shows usage and invoices by billing period.** Subscriptions that existed before October 12 keep renewing on the 1st. Service tokens for the REST API can now be limited to one project and expire. Prisma ORM 8 adds mixins, which let several models share the same fields, and a full-text index that covers several fields with weights. Prisma Studio in the Console has a new release with fixes going back to July. + +If you run the `prisma` tool or a Composer app on Node.js older than 22.18, on 24.0 to 24.10, or on the 23 or 25 line, if your scripts create service tokens through the API, if a client keeps a long-lived connection open to a Prisma Compute app, or if you are on a Prisma ORM 8 release candidate older than rc.18, see "What you need to do" below. Prisma Postgres Early Access databases are still deleted on **November 1, 2026**, and Accelerate is retired on **December 1, 2026**. + +## Your billing period starts when you upgrade + +When you upgrade a workspace to a paid plan, the plan now renews at 00:00 UTC on that day of each month, or on the last day of a shorter month. Workspaces that upgraded before October 12 keep renewing on the 1st, and nothing changes for them. Before, every subscription renewed on the 1st, so the first invoice covered a prorated part of a month and the plan's included usage was shared with the days before the upgrade. Now the first invoice covers a full month from the upgrade, usage from the Free plan before the upgrade does not count against the paid plan's allowance and is not billed on the first paid invoice, and the plan's limits reset on the renewal day. If your workspace was paused for reaching its spend limit, the pause now ends on that day too, and the emails at 75% and 100% of a spend limit are sent at most once per period. + +The Console follows the same period. The usage page's selector reads **Current billing period** and **Previous billing period**, with the dates of your own cycle, and the **Previous invoice** card groups invoices by period, so a proration invoice from a mid-cycle plan change no longer counts as the previous invoice. On the billing settings page, the operations meter counts your cycle and says when it resets, and the projects list column that said **Operations · 30d**, which was never a 30-day window, now says **Operations · this period**. Free workspaces, which have no renewal day, still see the calendar month. + +Subscriptions bought through the Vercel Marketplace follow the same rule, and Vercel's plan listing now says the invoice comes monthly on the day you upgrade. The [billing](https://www.prisma.io/docs/console/more/billing) docs page explains when the plan fee and the usage are charged, and how to cancel. + +
+ See your billing period + Read the billing docs +
+ +## Give a service token access to one project, and an expiry + +A service token is the credential a script or an integration uses to call the [REST API](https://www.prisma.io/docs/rest-api). Until now, every token could do everything in the workspace and never expired, so a leaked token stayed valid until someone noticed. When you create a token in the Console now, you choose **Full Workspace** or pick one project, and the token expires after 90 days unless you choose 7, 30, or 365 days, a date of your own, or no expiry. Tokens you created before keep their full workspace access and never expire, as before. + +The API takes the same choices: [`POST /v1/workspaces/{workspaceId}/service-tokens`](https://www.prisma.io/docs/rest-api/endpoints/service-tokens/post-workspaces-by-workspace-id-service-tokens) accepts an optional `projectId` and `expiresAt`, defaults to a 90-day expiry, and returns the token's scope and expiry. The credential that a GitHub Actions deploy receives through OpenID Connect now covers only the project its repository is connected to, so a workflow in one repository cannot touch another project. + +```bash title="Terminal" +curl -X POST https://api.prisma.io/v1/workspaces/$WORKSPACE_ID/service-tokens \ + -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ + -d '{"name": "ci-deploy", "projectId": "'$PROJECT_ID'", "expiresAt": "2027-01-14T00:00:00Z"}' +``` + +
+ Create a token in the Console + Read about REST API authentication +
+ +## Share fields across models, and search several fields at once + +In a Prisma ORM 8 schema, you can now declare a set of fields once and include it in any model. A `model mixin` block holds the fields and attributes, and `+Name` inside a model includes them, so `createdAt` and its index are written once instead of in every model. An `enum mixin` does the same for enum values. Your editor completes, renames, and navigates to mixins like any other declaration. ([docs](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#mixins), [#30675](https://github.com/prisma/orm/pull/30675)) + +```prisma title="prisma/schema.prisma" +model mixin Timestamps { + createdAt DateTime @default(now()) + deletedAt DateTime? + + @@index([createdAt]) +} + +model Post { + +Timestamps + id Int @id @default(autoincrement()) + title String +} +``` + +A full-text index on Postgres can now cover several fields, with the fields that matter most weighted higher. `@@fullTextIndex([[title, subtitle], body], name: "post_search")` ranks a match in the title above a match in the body. A query searches the index by naming it. In Prisma ORM 8, `where` and `orderBy` take a function that receives the model's fields, and that function now receives a second argument with the query functions, `fns`, and the model's indexes. Here `db.orm.public.Post` is the `Post` model in the `public` PostgreSQL schema, and `websearchToTsquery` turns the user's search text into a query the way a web search box reads it: ([#30562](https://github.com/prisma/orm/pull/30562), [#30676](https://github.com/prisma/orm/pull/30676)) + +```ts title="src/search.ts" +import { websearchToTsquery } from "@prisma/orm-postgres/target/full-text"; + +const q = websearchToTsquery(input); + +const posts = await db.orm.public.Post.select("id", "title") + .where((p, { fns, indexes }) => fns.fullTextMatches(indexes.post_search, q)) + .orderBy((p, { fns, indexes }) => fns.fullTextRank(indexes.post_search, q).desc()) + .all(); +``` + +The [full-text search](https://www.prisma.io/docs/orm/reference/orm-client#full-text-search) reference covers the other ways to build a search and the `language` option. + +Prisma ORM 8 is still a release candidate, and these changes arrived in `8.0.0-rc.18` of the library packages, such as `@prisma/orm-postgres`, which replace `@prisma/client`. The command-line tool, `prisma`, is released separately with its own version numbers; `prisma@8.0.0-rc.23` is the one that goes with this library release, and it also runs Prisma Compute deploys for Prisma ORM 7 apps. The release also adds the following: + +- **Read one record by a unique key.** `db.orm.public.User.whereUnique({ email }).first()` selects at most one record, as `findUnique` did in Prisma ORM 7, so chaining `all()` or `limit()` after `whereUnique` is a type error. `firstOrThrow()` reads one row and rejects with the error code `RUNTIME.NO_ROWS` when nothing matches, on Postgres, SQLite, and MongoDB. ([docs](https://www.prisma.io/docs/orm/fundamentals/reading-data), [#30670](https://github.com/prisma/orm/pull/30670), [#30644](https://github.com/prisma/orm/pull/30644)) +- **Rename on MongoDB.** `migration plan` and `db update` now carry out `--rename` on MongoDB: a model rename renames its collection and keeps its documents and indexes, and a field rename renames the field in every document. ([#30691](https://github.com/prisma/orm/pull/30691)) +- **Send warnings to your logger.** The client constructors, `postgres()`, `postgresServerless()`, `sqlite()`, and `supabase()`, take a `log` option, so the warnings Prisma ORM prints about your queries, and errors that middleware swallowed, reach your own logger. ([#30707](https://github.com/prisma/orm/pull/30707)) +- **Compose raw SQL.** The `sql` tag interpolates other `sql` values, so `` sql`${owner} AND deleted_at IS NULL` `` builds a predicate from pieces instead of joined strings. ([#30558](https://github.com/prisma/orm/pull/30558)) +- **Rename a symbol in your editor.** The language server renames models, fields, and types across every schema file, and go to definition works on the name inside a type argument such as `pg.enum(OrderStatus)`. ([#30633](https://github.com/prisma/orm/pull/30633)) + +
+ Read the schema reference + See the rc.18 release notes +
+ +## What you need to do + +- **If your scripts create service tokens through the API**, decide whether they should expire. A token created without `expiresAt` now expires after 90 days. Pass `"expiresAt": null` to keep creating tokens that never expire, or a date to choose your own. Tokens that already exist are not affected. +- **If you run the `prisma` tool or a Composer app on Node.js older than 22.18, on 24.0 to 24.10, or on the 23 or 25 line**, move to a supported version. Since `prisma@8.0.0-rc.23`, the `prisma` package, and since Composer 0.30.0 the Composer packages, declare Node.js 22.18 or newer on the 22 line, 24.11 or newer on the 24 line, or 26 or newer. The `@prisma/orm-*` library packages declare no range. On other versions, npm and pnpm print a warning, pnpm with `engine-strict` refuses to install, and Yarn 1 refuses too. The Prisma ORM 7 packages are not affected. The [supported versions](https://www.prisma.io/docs/orm/supported-versions) page lists every minimum. ([prisma-cli#343](https://github.com/prisma/prisma-cli/pull/343)) +- **If you are on a Prisma ORM 8 release candidate older than `8.0.0-rc.18`**, follow the [rc.18 upgrade guide](https://github.com/prisma/orm/blob/v8.0.0-rc.18/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.17-to-8.0.0-rc.18/). Its `instructions.md` gives the command for the script that rewrites the raw SQL in your `.prisma` files. Then run `prisma contract emit`. The contract is a generated file that describes your schema, which the client and the migration commands read, much as `prisma generate` wrote the client in Prisma ORM 7. Then follow the breaking changes below, and if you wrote middleware, rename its hooks. +- **If a client keeps a long-lived connection open to a Prisma Compute app**, such as a server-sent events stream or a WebSocket, expect it to be closed 30 seconds after a deploy replaces the version it was connected to. The old version is now stopped 30 seconds after the new one takes over. Before, it kept running until its last client disconnected, and a deploy could time out waiting for it. Make your client reconnect. +- **Prisma Postgres Early Access databases are deleted on November 1, 2026 at 00:00 UTC.** Follow the [migration guide](https://www.prisma.io/docs/postgres/migrate-from-ea-to-ga) before then. +- **Accelerate is retired on December 1, 2026.** [Switch to a pooled connection or to the serverless driver](https://www.prisma.io/docs/postgres/database/switch-from-accelerate), or [keep your own database and connect to it without Accelerate](https://www.prisma.io/docs/accelerate/keep-your-database). + +## Breaking changes in Prisma ORM 8.0.0-rc.18 + +These apply only if you upgrade from an earlier release candidate. The [rc.18 release notes](https://github.com/prisma/orm/releases/tag/v8.0.0-rc.18) list every change, including the ones for extension authors, and link the upgrade guide. + +- **Raw SQL in a schema is a `sql` literal.** `@@index(where:)`, `@@index(expression:)`, `@@fullTextIndex(where:)`, `@@check(expression:)`, and a policy's `using` and `withCheck` take ``sql`...` ``, and a quoted string is refused with `PSL_VALUE_TYPE_INCOMPATIBLE`. The upgrade guide's script rewrites every `.prisma` file. In a TypeScript contract the same fields take a `sql` value. ([#30550](https://github.com/prisma/orm/pull/30550)) +- **Middleware hooks are renamed.** `beforeQuery` and `beforeExecute` become `beforeEncode`, `interceptQuery` and `interceptExecute` become `intercept.onQuery` and `intercept.onExecute`, `afterQuery` and `afterExecute` become `activityEnded`, and `afterTransaction` becomes `activityFinalized`. `activityEnded` also fires for a query whose results your code never finished reading, so a middleware that records timings checks `result.outcome`. ([docs](https://www.prisma.io/docs/orm/middleware/how-middleware-works), [#30703](https://github.com/prisma/orm/pull/30703)) +- **A full-text index gets a new generated name.** Run `prisma contract emit`, then `prisma migration plan`, which renames the index in place. Avoid `db update` for a large index, because it drops and rebuilds it. ([#30562](https://github.com/prisma/orm/pull/30562)) +- **The SQL client accepts only field names.** A column name that differs from its field name, such as `user_id` for the field `userId`, now throws `ORM.FIELD_UNKNOWN`. ([#30667](https://github.com/prisma/orm/pull/30667)) +- **A type change that can lose values asks first.** `prisma migration plan` fails with `CLI.CONSENT_REQUIRED` until you answer: `--convert User.age` means you will write the conversion yourself in the migration, and `--delete User.age` means you accept that values the database cannot convert are lost. A new required field gets a placeholder value in existing rows unless you pass `--backfill User.age` and fill them yourself. On MongoDB, removing a field now asks too, because the plan removes it from every document. ([#30695](https://github.com/prisma/orm/pull/30695), [#30691](https://github.com/prisma/orm/pull/30691)) +- **A query fragment is made from the plain model, not from a filtered one.** A fragment is a reusable piece of a query, introduced in the [October 9 entry](/changelog/2026-10-09). `db.orm.public.Post.where(...).fragment(body)` now throws `ORM.ARGUMENT_INVALID`; move the `where` into the fragment's body. The types `Fragment` and `FieldFragment` are now `QueryFragment` and `DeclaredFieldsFragment`. ([#30652](https://github.com/prisma/orm/pull/30652), [#30673](https://github.com/prisma/orm/pull/30673)) +- **A Prisma 7 schema's `@ignore` and `@@ignore` objects are now kept in the contract**, where Prisma ORM 8 used to drop them. If your Prisma 7 schema uses them and Prisma ORM 8 reads it, run `prisma contract emit`, then `prisma db sign --db "$DATABASE_URL"` against each database, which records that the database already matches the new contract. If Prisma ORM 8 already manages your migrations, run `prisma migration plan` instead of signing. ([#30672](https://github.com/prisma/orm/pull/30672)) +- **Do not declare the same model both at the top level and inside `namespace public { ... }`.** On Postgres they now share one set of names, so the second declaration is refused with `PSL_DUPLICATE_DECLARATION`. ([#30700](https://github.com/prisma/orm/pull/30700)) +- **Types are stricter.** `connect` and `disconnect` no longer accept `null` for a nullable unique column, a model with no fields cannot be read or written, and on the object that `db.prepare(...)` returns, `all` and `aggregate` must be called as its methods rather than copied into variables. ([#30663](https://github.com/prisma/orm/pull/30663), [#30705](https://github.com/prisma/orm/pull/30705)) +- **`db.nativeEnums` lists native enum types only.** Read an `enum` block's members through `db.enums`. ([#30661](https://github.com/prisma/orm/pull/30661)) + +## Prisma Studio + +Prisma Studio in the Console is on `@prisma/studio-core` 0.34.1, the first release since July. The schema visualizer now remembers where you dragged each table, with a **Reset layout** action, and the data grid's footer shows how many rows the current result set holds, after filters and search. + +The release also fixes bugs that had been waiting since the summer. Editing a Postgres enum array cell no longer fails with `Update Operation failed`. Column widths and order no longer reset when you pin or unpin a column, horizontal scrolling in a wide table no longer jumps, and the last column can be reached. In the `@prisma/studio-core` package, which runs Studio against your own database, a connection string with libpq SSL parameters such as `sslrootcert` and `sslmode` now connects instead of being refused, and SQLite date and time edits no longer save `NaN`. Staged edits on rows that were loaded by scrolling now save. A failed **Refresh table** keeps the last rows visible with an inline error and a retry. Postgres types show their common names, so `int8` is shown as `bigint`. In a schema view with no comparison, models are no longer all labelled "unchanged". + +Opening Studio in the Console also no longer runs its schema queries twice against your database on every page load. + +## Prisma Compute + +Prisma Composer is the TypeScript description of a Prisma Compute app's services and databases in `prisma.config.ts`. When you connect a repository, the Console opens a pull request that adds it. Connecting a GitHub repository to a project now works in two more situations. If Prisma cannot set up deploys for a repository yet, you can still create the project and connect it, and the project page shows what to do next. A repository that already has a Composer config and a deploy workflow can be connected to an existing project, where before it showed "Not supported yet" and the connection was not saved. A refresh button beside the GitHub account picker lets you grant the Prisma GitHub App access to more repositories and see them without reloading the page, and a name you type into the project picker is carried into the new project. + +Clicking a managed Postgres database in a project's **Topology** view, the diagram of its services and databases, now opens its recorded schema in Studio's migrations view, and you can switch to the diff against the main branch's database. You see the schema after your first deploy that runs with `prisma@8.0.0-rc.23` or newer; the `prisma` tool runs the deploy even if your app is on Prisma ORM 7. {/* plain-language:defined */} + +Enrolled agents, the coding agents you give a credential of their own, introduced in the [October 2 entry](/changelog/2026-10-02), now have settings per workspace. On **Settings → Agents**, you choose which workspaces an agent may work in and whether it may use every project or only the ones you pick, and you can give each agent a name and an icon. Approval requests are shown throughout the Console, not only on the agent's page. + +Under `prisma dev`, which runs your app on your machine, services now receive their local ports in dependency order, so a service that another one connects to is ready first. ([composer#350](https://github.com/prisma/composer/pull/350)) + +## Prisma Console + +The sign-in page at `auth.prisma.io`, which the Prisma CLI, the Prisma MCP server, and OAuth clients send you to, now has an email and password form next to GitHub and Google, and your existing Console password works there. You can also create an account on that page, with a confirmation email, and reset a forgotten password with a link that lasts six hours. A reset signs you out everywhere. Because the sign-in service was rebuilt, everyone signed in at `auth.prisma.io` had to sign in once more, and a session there now lasts seven days. + +Uninstalling the Prisma integration from a Vercel team on a paid plan now completes; before, its last step failed. The remaining metered usage is invoiced within 24 hours, and the current month's plan fee, which is paid in advance, is not refunded. + +## Docs and website + +- Two new directories of short answers: [Prisma Postgres guides](/postgres/guides) and [Prisma Compute guides](/compute/guides). Each page answers one question, such as how to give TypeScript tests a database of their own or how to choose a database region, gives the fix that works on any host, then says where Prisma fits. Agents can read each one as Markdown. +- A new [compare](/compare) directory collects the comparison pages, with new pages for [Kysely](/compare/kysely), [Mongoose](/compare/mongoose), and [Convex](/compare/convex). +- The [HIPAA](/postgres/hipaa) page explains what Prisma Postgres covers under a Business Associate Agreement and links a sample agreement. The Data Processing Agreement is now a web page at [/legal/dpa](/legal/dpa), with the BAA at [/legal/baa](/legal/baa) and every legal document listed at [/legal](/legal). +- Two new guides: [build a marketing site with Astro](https://www.prisma.io/docs/guides/compute/astro-marketing-site) on Prisma Compute, the first in a new "Build on Compute" category for apps with or without Prisma ORM, and [Remix 3](https://www.prisma.io/docs/guides/frameworks/remix) with Prisma ORM, which ends with a deploy to Prisma Compute. + +## Fixes + +### Prisma Compute + +- A deploy can no longer remove an app's custom domain. If the domain cannot be moved to the new deployment, the deploy fails and the old deployment keeps serving it. Before, the domain and its certificate were deleted with the old deployment. +- Downgrading to a plan without Static IPs is no longer blocked by connections you already deleted, and the message says what to do with the ones that remain. The Accelerate settings page no longer shows `Couldn't load settings` when Accelerate is disabled. + +### Prisma ORM 8 + +- `prisma db verify --strict` passes on a database that Prisma ORM 7 built, and `prisma contract infer` no longer prints a model for Prisma 7's `_prisma_migrations` table. ([#30671](https://github.com/prisma/orm/pull/30671)) +- The `budgets()` middleware now enforces `maxRows` on the rows a query returns. The check never ran before, so a read over the limit now fails with `BUDGET.ROWS_EXCEEDED`. ([#30703](https://github.com/prisma/orm/pull/30703)) +- An update with no changes, `update({})`, now returns the first matching row, and `updateAll({})` the matching rows. Before, they returned `null` and no rows. ([#30680](https://github.com/prisma/orm/pull/30680)) +- A migration that makes a field required while rows have no value for it fails with a summary that counts those rows and names the fix. ([#30695](https://github.com/prisma/orm/pull/30695)) +- A repeated `db update` on a MongoDB database with a time-series collection no longer fails with "Cannot change immutable collection option". ([#30691](https://github.com/prisma/orm/pull/30691)) + +## Guides and articles + +- [We closed 330 of your most-requested issues with Prisma ORM 8](https://www.prisma.io/blog/prisma-orm-8-closes-330-most-requested-issues): the ten most-upvoted issues before and after, from typed JSON and polymorphism to partial unique indexes and PostGIS, then the other 320 by theme. +- [How to host a test version of your app without replacing production](https://www.prisma.io/blog/host-a-test-version-without-replacing-production): deploy a branch to a preview or staging URL with a test database, on Fly.io, Netlify, Prisma Compute, Railway, Render, and Vercel. +- [Serverless Postgres compared (2026)](https://www.prisma.io/blog/serverless-postgres), updated: Neon, Supabase, Amazon RDS and Aurora, and Prisma Postgres by stage, from free tiers to read replicas. +- [From a local Postgres database to production](https://www.prisma.io/blog/from-local-to-production-with-prisma-postgres), updated: Prisma Postgres, Neon, Render, Railway, and Supabase compared for hosting a laptop database online. + +--- + +*Need help applying these changes in production? [Prisma Enterprise Support](/enterprise) can help with schema design, performance, security, and compliance.* diff --git a/apps/site/content/changelog/2026-10-23.mdx b/apps/site/content/changelog/2026-10-23.mdx new file mode 100644 index 00000000000..06dab08fbcc --- /dev/null +++ b/apps/site/content/changelog/2026-10-23.mdx @@ -0,0 +1,166 @@ +--- +title: "Script your local Prisma Compute app with prisma dev --detach, dev url, and dev stop" +date: "2026-10-23" +version: "2026-10-23" +slug: "2026-10-23" +headline: "Script your local Prisma Compute app with prisma dev --detach, dev url, and dev stop" +tags: + - "Prisma" + - "Prisma Compute" + - "Prisma ORM" + - "Prisma Postgres" +canonical: "/changelog#log2026-10-23" +metaDescription: "prisma dev can now run your app in the background, print where each service answers, and stop it, so scripts and agents can drive it. Also new: piped prisma commands print plain data and need --json for JSON, Prisma ORM 8 writes generated ids with @onCreate, and Prisma ORM 7.10.1 fixes nested transactions." +share: + active: true + content: "Look at this page: " +--- +**`prisma dev` can now start your Prisma Compute app on your machine and return, print where each service answers, and stop the app, so a script or a coding agent can drive it without watching a terminal.** When you pipe a Prisma 8 `prisma` command into another program, it now prints plain data instead of JSON, and `--json` gives you the JSON, which changes scripts that parsed the old output. In Prisma ORM 8, a value the client generates, such as a UUID, is now written `@onCreate(uuid())`, and `@default` means a database default. Prisma ORM 7.10.1 fixes a bug where a nested transaction could make later transactions run inside the wrong one, and makes Prisma Migrate refuse a shadow database that is the main database, which could drop your real schema. + +If you have scripts that read JSON from a piped `prisma` command, or you are on a Prisma ORM 8 release candidate, see "What you need to do" below. Prisma Postgres Early Access databases are still deleted on **November 1, 2026**, and Accelerate is retired on **December 1, 2026**. + +## Run your app locally in the background and ask where it answers + +In the Prisma 8 command-line tool, `prisma dev` runs your Prisma Compute app on your machine, on local emulators that stand in for Prisma Compute, Prisma Postgres, and buckets, with no Prisma account. If your `package.json` pins `prisma@7`, nothing in this section changes your commands. The app is described by [Prisma Composer](https://www.prisma.io/docs/composer), the `composer` section of `prisma.config.ts` that the Console's setup pull request adds to a repository. Until now `prisma dev` stayed in the foreground, so a script or an agent had to run it in the background itself and watch its output for the word "ready". It also printed the port of each service only at startup, and the Composer guide hard-coded `localhost:3001`, which was only right when nothing else held that port. + +The tool is the `prisma` package, released separately from the Prisma ORM 8 library packages, so its version numbers differ from theirs, and it runs Prisma Compute deploys for Prisma ORM 7 apps too. Since `prisma@8.0.0-rc.24`, `prisma dev module.ts --detach`, where `module.ts` is the app's entry file, brings the app up, waits until every service answers, prints the URLs, and returns with exit code 0, leaving the app running. `prisma dev url
` prints where one part of the app answers, bare, so you can pass it straight to `curl`. `prisma dev stop` stops the app's services and local databases and keeps their data. `prisma emulator list` shows every service, database, and bucket the local stand-ins are running, from any directory on the machine. ([composer#357](https://github.com/prisma/composer/pull/357), [composer#363](https://github.com/prisma/composer/pull/363), [prisma-cli#355](https://github.com/prisma/prisma-cli/pull/355)) + +```bash title="Terminal" +npx prisma dev module.ts --detach +curl "$(npx prisma dev url gateway)" +npx prisma dev url catalog.database # prints the local connection string +npx prisma dev stop +``` + +An address is the part's name in the app, dotted when it sits in a module: `gateway` is the service `gateway`, and `catalog.database` is the database named `database` inside the `catalog` module. Since `prisma@8.0.0-rc.28`, an address starts with the app's name, as the [October 30 entry](/changelog/2026-10-30) describes. `prisma dev` prints each service's address next to its URL at startup. Two checkouts of the same app can now run `prisma dev` side by side, each with its own services, databases, and ports. Before, the second one took over the first one's processes, and `--fresh` in either checkout wiped both. A service also keeps its port between runs now, and stopping `prisma dev` stops the app's local Postgres servers as well. ([composer#354](https://github.com/prisma/composer/pull/354), [composer#356](https://github.com/prisma/composer/pull/356)) + +
+ Read about local development + See the emulator reference +
+ +## Generate ids in your app with @onCreate, and keep @default for the database + +In a Prisma ORM 8 schema, `@default` now means a value the database fills in, and a value your app generates when it creates a row is written with `@onCreate(...)`. `@default(uuid())` is refused with `PSL_GENERATOR_IN_DEFAULT`, and `@onCreate(uuid())`, `@onCreate(cuid(2))`, `@onCreate(ulid())`, and `@onCreate(nanoid())` take its place. `@onUpdate(now())` fills a field on every update. `@default(now())` and `@default(autoincrement())` stay as they are, because the database runs them. You can put both on one field: `createdAt DateTime @default(now()) @onCreate(now())` means your app sets the time when it creates the row, and the database sets it when another program inserts one. The [schema reference](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#generated-values) lists each function and the column types it fits. ([#30780](https://github.com/prisma/orm/pull/30780)) + +```prisma title="prisma/schema.prisma" +model Post { + id String @id @onCreate(uuid(7)) + slug String @onCreate(nanoid(12)) + createdAt DateTime @default(now()) + updatedAt DateTime @onCreate(now()) @onUpdate(now()) +} +``` + +Prisma ORM 8 is still a release candidate, and this change arrived in `8.0.0-rc.19` of the library packages, such as `@prisma/orm-postgres`. The upgrade guide ships a script that rewrites your schema files. This change does not alter the contract, the generated file that `prisma contract emit` writes from your schema and the client reads, so it needs no migration. Some other rc.19 changes do; they are listed below. In `8.0.0-rc.20`, you can also put these attributes on a type alias, so every field that uses the alias behaves the same way, and two aliases come ready-made: ([#30819](https://github.com/prisma/orm/pull/30819)) + +```prisma title="prisma/schema.prisma" +model Post { + id Int @id @default(autoincrement()) + createdAt temporal.CreatedAt + updatedAt temporal.UpdatedAt +} +``` + +
+ Read the schema reference + See the rc.19 release notes +
+ +## Rename a PostgreSQL schema or change a relation's actions with a migration + +Prisma ORM 8 migrations on Postgres can now rename a PostgreSQL schema, which a Prisma ORM 8 schema file calls a namespace, and move a table into another one. `prisma migration plan --rename billing:finance` renames the schema, and `prisma migration plan --rename public.Invoice:billing.Invoice` moves the table with its rows, constraints, indexes, and policies. If you remove a namespace from your schema file, `prisma migration plan` and `prisma db update` now ask what to do with each table in it, where before they left the tables in place without a word. ([#30823](https://github.com/prisma/orm/pull/30823)) + +`prisma migration plan` can also change a relation's `onDelete` or `onUpdate` action, and change or remove a primary key, on Postgres. Both changes used to be refused with `MIGRATION.PLANNING_FAILED`. And if you type a Prisma ORM 7 command such as `prisma migrate dev` or `prisma migrate deploy` in a Prisma ORM 8 project, it now exits with `CLI.COMMAND_MOVED` and names the command to use instead. ([#30774](https://github.com/prisma/orm/pull/30774)) + +When a migration fails, the message now names what got in its way, such as `the database already has table "user"`, and says whether the database changed. ([#30814](https://github.com/prisma/orm/pull/30814)) + +## What you need to do + +- **If a script, a CI step, or an agent reads JSON from a piped `prisma` command**, add `--json` to that command. Since `prisma@8.0.0-rc.24`, a `prisma` command whose output goes to a pipe, a file, or `$(...)` prints plain text. A command that lists things prints one tab-separated line per item. A command that shows one thing prints `keyvalue` lines. A command that returns one value, such as a URL, prints it bare. A command that only changes something prints nothing, and its exit code tells you whether it worked. Before, a piped command always printed JSON. This is the Prisma 8 tool; the Prisma ORM 7 `prisma` command never printed JSON when piped and is not affected. The ORM commands of the Prisma 8 tool follow the same rule since `prisma@8.0.0-rc.26`, and `prisma deploy` since `prisma@8.0.0-rc.27`; on rc.24 and rc.25 a piped ORM or deploy command prints nothing. So `prisma migration status | jq ...` now needs `prisma migration status --json | jq ...`. ([prisma-cli#353](https://github.com/prisma/prisma-cli/pull/353), [#30835](https://github.com/prisma/orm/pull/30835)) +- **If you are on a Prisma ORM 8 release candidate older than `8.0.0-rc.18`**, first follow the rc.18 steps in the [October 16 entry](/changelog/2026-10-16), then continue here. +- **If you are on a Prisma ORM 8 release candidate older than `8.0.0-rc.20`**, follow the [rc.19 upgrade guide](https://github.com/prisma/orm/blob/v8.0.0-rc.19/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.18-to-8.0.0-rc.19/) and then the [rc.20 upgrade guide](https://github.com/prisma/orm/blob/v8.0.0-rc.20/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.19-to-8.0.0-rc.20/). Each ships scripts that rewrite your schema and your code, and each ends with `prisma contract emit` and `prisma db sign` against every database, which records in the database that it matches the new contract. The newest library version in this entry is `8.0.0-rc.20`, which goes with the tool `prisma@8.0.0-rc.26` or newer. The breaking changes below are the ones most likely to affect an app; the release notes list the rest. +- **If your Composer app includes the `auth` module**, run `prisma db sign --db ` against each of its databases after you move the app's `@prisma/composer` packages to 0.34.0, which needs `prisma@8.0.0-rc.26` or newer. The module's contract changed, and until each database is signed, `prisma deploy` and `prisma dev` fail at the migration step. The steps are in the auth module's [README](https://github.com/prisma/composer/blob/main/packages/1-prisma-cloud/2-shared-modules/auth/README.md), under "Upgrading to Composer 0.34.0". +- **If you are on Prisma ORM 7**, update to [7.10.1](https://github.com/prisma/orm/releases/tag/7.10.1) if you nest `$transaction` calls, as described under "Prisma ORM" below. +- **Prisma Postgres Early Access databases are deleted on November 1, 2026 at 00:00 UTC.** Follow the [migration guide](https://www.prisma.io/docs/postgres/migrate-from-ea-to-ga) this week. +- **Accelerate is retired on December 1, 2026.** [Switch to a pooled connection or to the serverless driver](https://www.prisma.io/docs/postgres/database/switch-from-accelerate), or [keep your own database and connect to it without Accelerate](https://www.prisma.io/docs/accelerate/keep-your-database). + +## Breaking changes between Prisma ORM 8 release candidates + +These apply only if you upgrade from an earlier release candidate to `8.0.0-rc.19` or `8.0.0-rc.20`. The release notes for [rc.19](https://github.com/prisma/orm/releases/tag/v8.0.0-rc.19) and [rc.20](https://github.com/prisma/orm/releases/tag/v8.0.0-rc.20) list every change, including the ones for extension authors. + +- **Values the client generates are written `@onCreate(...)`.** `@default(uuid())`, `@default(cuid(2))`, `@default(ulid())`, and `@default(nanoid())` are refused. The upgrade script rewrites them. ([#30780](https://github.com/prisma/orm/pull/30780)) +- **The client constructor takes the contract as a value.** Where you wrote `postgres({ contractJson, url })`, you now write `const contract = contractFromJson(contractJson)` once, with `contractFromJson` imported from `@prisma/orm-postgres/static`, and pass `postgres({ contract, url })`. The same applies to `sqlite()`, `supabase()`, and `mongo()`. The upgrade script rewrites your source files. ([#30748](https://github.com/prisma/orm/pull/30748)) +- **Date, time, interval, and bytes defaults are written with tags.** `@default("2024-01-01T00:00:00Z")` on a `DateTime` column becomes ``@default(timestamptz`2024-01-01T00:00:00Z`)``, a `Date` default takes `date`, and a `Bytes` default takes `bytea` with hexadecimal. Run `prisma contract emit`, then `prisma db sign` against every database. ([#30750](https://github.com/prisma/orm/pull/30750)) +- **`@noCheck` is removed.** Write `String?[]` for a list that allows `null` elements, and delete `@noCheck(membership)`. The upgrade script rewrites stored contracts first; then sign every database. ([#30741](https://github.com/prisma/orm/pull/30741)) +- **A piped ORM command prints data lines, not JSON.** Add `--json` wherever a script reads JSON from `prisma contract`, `prisma db`, `prisma migration`, or `prisma orm init`, as described above. ([#30835](https://github.com/prisma/orm/pull/30835)) +- **If your schema uses a `types {}` alias, re-emit and sign.** The contract now records each column's real type instead of the alias name. Run the rc.20 script, then `prisma contract emit`, then `prisma db sign` against every database. Nothing in the database changes; the sign only records that it matches the new contract. In a schema written in TypeScript, write an alias as a constant such as `field.column(type.VarChar(64))`. ([#30819](https://github.com/prisma/orm/pull/30819)) +- **Type arguments are values.** `VarChar("255")` is refused; write `VarChar(255)`. An enum member is a value of its type too, so a `numeric` enum writes `Half = 0.5`, unquoted. ([#30801](https://github.com/prisma/orm/pull/30801), [#30790](https://github.com/prisma/orm/pull/30790)) +- **A SQL builder insert must include every column the database requires.** Leaving out a column that is not nullable and has no default is now a type error that names the column, where it used to compile and then fail in the database. ([#30830](https://github.com/prisma/orm/pull/30830)) +- **A MongoDB field keeps its schema name in code.** A field declared `id ObjectId @id @map("_id")` is `id` in rows, in `where`, and in write data, where it was `_id`. Run `prisma contract emit`, then the upgrade script, which rewrites migration snapshots. ([#30779](https://github.com/prisma/orm/pull/30779)) +- **MongoDB contracts written in TypeScript get a collection validator**, as schema files already did. Fix any document the validator would refuse, then apply it with `prisma db update` or a migration. ([#30773](https://github.com/prisma/orm/pull/30773)) +- **If you wrote a cache key function for the cache middleware, check it before upgrading.** The middleware now caches a whole ORM read under the key named in `cacheAnnotation({ key })`, and your `deriveKey` function no longer applies to ORM reads, only to SQL builder queries. If `deriveKey` was what kept one tenant's reads apart from another's, give each annotated ORM read a key that includes the tenant, or one tenant's cached rows can be served to another. ([#30749](https://github.com/prisma/orm/pull/30749)) +- **Regenerate migrations you have not applied yet.** For each unapplied migration, run `node migration.ts` in its folder again, as the upgrade guide shows, so its checks are rewritten in the new form. ([#30752](https://github.com/prisma/orm/pull/30752)) +- **A failed migration reports its own error code.** `MIGRATION.RUNNER_FAILED` is gone, and a failure reports `MIGRATION.SCHEMA_VERIFY_FAILED`, `MIGRATION.PRECHECK_FAILED`, or `MIGRATION.POSTCHECK_FAILED` with details. ([#30791](https://github.com/prisma/orm/pull/30791)) +- **`db verify --json` and `db sign --json` report schema differences in `meta.schemaIssues`**, each with a `path`, `expected`, and `actual`. ([#30814](https://github.com/prisma/orm/pull/30814)) +- **Supabase clients run every role operation through `forRole(binding)`**, and the `pg` option takes a pool, not a client. ([#30828](https://github.com/prisma/orm/pull/30828)) +- **`using` is reserved on every collection**, so a custom collection class with its own `using` member must rename it. ([#30717](https://github.com/prisma/orm/pull/30717)) + +## Prisma ORM + +Prisma ORM 7.10.1 fixes a bug in nested interactive transactions. If you passed the same options object to a nested `tx.$transaction(...)` and later to a top-level `prisma.$transaction(...)`, the nested call wrote the outer transaction's id into that object, so every later transaction that used the object was treated as nested inside the old one. It then failed with `P2028` if the old transaction had committed, or silently ran inside another request's transaction if it was still open. Prisma Client no longer changes the options object. Prisma Migrate also now refuses, with `P3025`, a shadow database URL that points at the main database. Before, `prisma migrate diff --from-migrations` with that setup dropped the real schema. The release also updates dependencies that had security advisories. ([#30368](https://github.com/prisma/orm/pull/30368), [prisma-engines#5851](https://github.com/prisma/prisma-engines/pull/5851)) + +Prisma ORM 8 `8.0.0-rc.19` and `8.0.0-rc.20` also add the following: + +- **Search a full-text index from the model.** Each full-text index gives its model a method under `using`, such as `db.orm.public.Post.using.post_search(query)`, and pgvector adds a nearest-neighbour search for each vector field. The methods chain with `where`, `orderBy`, and `limit`. ([docs](https://www.prisma.io/docs/orm/reference/orm-client#package-methods-with-using), [#30717](https://github.com/prisma/orm/pull/30717)) +- **Build a query without a database.** `db.toSql(plan)` renders any built query as `{ sql, params }`, and `db.query(plan)` and `db.execute(plan)` run one directly. ([#30802](https://github.com/prisma/orm/pull/30802)) +- **Declare a column of any database type.** ``Raw(sql`ltree`)`` declares a column whose type Prisma ORM 8 does not know. Migrations create it from the text, and the client reads and writes its values as `unknown`. ([#30745](https://github.com/prisma/orm/pull/30745)) +- **Load a Prisma 7 schema with `Unsupported(...)` fields.** The column stays in the database but does not appear on the model, as in Prisma 7's client. ([#30788](https://github.com/prisma/orm/pull/30788)) +- **Use your own collection classes everywhere.** If you extend a model's collection, the object you query through, with a class of your own, every SQL client now takes those classes as the `collections` option and uses them on `db.orm`, in transactions, and on serverless connections. A transaction also offers the client's `sql`, `orm`, `raw`, and `prepare` members. ([#30776](https://github.com/prisma/orm/pull/30776), [#30789](https://github.com/prisma/orm/pull/30789)) +- **Pass a plain string to a `VarChar` or `Numeric` field.** Filters and writes take each field's input type, so a `Varchar<50>` field accepts a string in `where` and `create`. ([#30709](https://github.com/prisma/orm/pull/30709)) +- **Infer more column types.** `prisma contract infer`, which writes a schema from an existing database as `db pull` did, now writes the shortest matching type for each column, and when a column's type is unknown it fails once and lists every such column instead of writing a schema that cannot be emitted. `Bit`, `VarBit`, and `Interval` are new. ([#30735](https://github.com/prisma/orm/pull/30735)) + +## Prisma Compute + +A `prisma deploy` that was interrupted while it created the app's services now resumes on the next deploy and uses what the interrupted deploy had already created. Before, the second deploy and every deploy after it failed, and the only way out was destroying the stage. ([composer#367](https://github.com/prisma/composer/pull/367)) + +A service whose schema has a pgvector column can now get a working client from its `postgres(contract)` dependency: import `pgvectorRuntime` from `@prisma/orm-extension-pgvector/runtime` and call `db.clientWith({ extensions: [pgvectorRuntime] })`. ([composer#369](https://github.com/prisma/composer/pull/369)) + +## Prisma Postgres + +Workspaces with a plan limit now get an email at 50% and at 90% of a monthly limit, once each per billing period. Before, the only email came after the limit was hit. + +Full backups of large databases now run faster, and a backup that runs long no longer has a second one started on top of it. + +## Docs and website + +- [Supported versions](https://www.prisma.io/docs/orm/supported-versions) states every minimum for Prisma ORM 8 on one page: Node.js, Bun, Deno, PostgreSQL, MongoDB, TypeScript, and the `temporal-polyfill` requirement on Node.js 22 and 24. +- [Advanced PostgreSQL](https://www.prisma.io/docs/orm/contract-authoring/advanced-postgresql) takes you from a row-level security need to a working setup, with the `policy_select` block, the role and grant to create once, and the `set_config` call inside a transaction. +- [A database on your machine](https://www.prisma.io/docs/prisma-orm/local-database) is for a reader with no database yet: PostgreSQL in Docker, the database that a new `npm create prisma` app starts itself, MongoDB, or a temporary hosted Prisma Postgres database from `npx create-db@latest`. +- [Bucket behavior](https://www.prisma.io/docs/storage/behavior) explains how hosted Object Store buckets behave: single region, strong consistency, conditional writes, one access key per bucket, and no versioning or soft delete. +- [Members and deletion](https://www.prisma.io/docs/console/more/workspaces) covers inviting and removing workspace members, handing a workspace to someone else, and what blocks deleting a database, project, or workspace. [Billing and cancellation](https://www.prisma.io/docs/console/more/billing) covers when charges happen and how to cancel. +- The [emulator](https://www.prisma.io/docs/cli/emulator) reference is new, and [local development](https://www.prisma.io/docs/composer/local-development) covers `dev url`, `dev stop`, and `--detach`. +- The [Clerk with Next.js](https://www.prisma.io/docs/guides/authentication/clerk/nextjs) guide now targets Prisma ORM 8 and Next.js 16 and ends with a deploy to Prisma Compute. The Prisma ORM 7 version is kept under [guides/v7](https://www.prisma.io/docs/guides/v7/authentication/clerk/nextjs). + +## Fixes + +### Prisma ORM 8 + +- A hand-written `setDefault` that changes an existing default is applied instead of skipped. ([#30752](https://github.com/prisma/orm/pull/30752)) +- When a raw SQL default fails the schema check because the database stores it in another form, the error shows both texts and the `sql` literal to write. ([#30740](https://github.com/prisma/orm/pull/30740)) +- On MongoDB, a typed `where` accepts `null`, an empty list, and a whole list on list fields, and a contract with a composite type that contains itself now emits instead of overflowing the stack. ([#30769](https://github.com/prisma/orm/pull/30769), [#30733](https://github.com/prisma/orm/pull/30733)) +- `db migrate` no longer says a failed apply changed nothing on MongoDB when earlier operations stayed applied. ([#30814](https://github.com/prisma/orm/pull/30814)) +- In the TypeScript builder, passing `undefined` to skip an argument no longer loses the arguments after it. ([#30830](https://github.com/prisma/orm/pull/30830)) + +### Prisma Compute + +- `prisma dev` reports a service as running only once its port accepts connections. ([composer#353](https://github.com/prisma/composer/pull/353)) +- `prisma dev stop` reports only what it stopped, and the help for `dev` and `deploy` says what each flag does. ([composer#368](https://github.com/prisma/composer/pull/368)) + +## Guides and articles + +- [Railway's security incident: how to secure your Prisma Postgres database, and what to do next](https://www.prisma.io/blog/railway-security-incident-lessons-and-migration): how to replace your database credentials after the October 21 incident and secure your other secrets, on any host. + +--- + +*Need help applying these changes in production? [Prisma Enterprise Support](/enterprise) can help with schema design, performance, security, and compliance.* diff --git a/apps/site/content/changelog/2026-10-30.mdx b/apps/site/content/changelog/2026-10-30.mdx new file mode 100644 index 00000000000..d6ff626600f --- /dev/null +++ b/apps/site/content/changelog/2026-10-30.mdx @@ -0,0 +1,171 @@ +--- +title: "Put a custom domain on a Prisma Compute preview branch" +date: "2026-10-30" +version: "2026-10-30" +slug: "2026-10-30" +headline: "Put a custom domain on a Prisma Compute preview branch" +tags: + - "Prisma" + - "Prisma Compute" + - "Prisma ORM" + - "Prisma Postgres" + - "Prisma MCP server" + - "REST API" +canonical: "/changelog#log2026-10-30" +metaDescription: "A custom domain can now point at a preview or staging branch of a Prisma Compute app, and you prove you own a domain with a TXT record before it is attached. Also new: every part of a Composer app has an address you can pass to prisma commands, and Prisma ORM 8 reads dates as JavaScript Date values again." +share: + active: true + content: "Look at this page: " +--- +**A custom domain can now point at a preview or staging branch of a Prisma Compute app, not only at production, and you prove that you own a domain with a DNS record before Prisma attaches it.** Every service, database, and bucket of a Prisma Compute app now has an address that starts with the app's name, such as `shop.api`, and you can pass that address to `prisma` commands instead of looking up an id. In Prisma ORM 8 on Postgres, a `DateTime` field now reaches your code as a JavaScript `Date` by default, and MySQL has its first packages as an early preview. + +If you deploy to Prisma Compute, read "What you need to do" before you raise the `prisma` version in your deploy workflow: the first deploy with `prisma@8.0.0-rc.28` or newer renames every part of the app and replaces its connection strings and access keys, and the entry file moves into `prisma.config.ts`. If you are on a Prisma ORM 8 release candidate, the date types change. See "What you need to do". Prisma Postgres Early Access databases are deleted on **November 1, 2026**, and Accelerate is retired on **December 1, 2026**. + +## Give a preview branch its own domain, and prove you own it first + +Until now, a custom domain could only be attached to a Prisma Compute app's production branch, so a staging environment lived on its generated `prisma.build` address. Now the same domain workflow works on every branch that has a live deployment. In the [Prisma Console](https://console.prisma.io), open the branch app's **Domains** page and add the hostname, and from the command line, since `prisma@8.0.0-rc.28`, pass `--branch` to the domain commands, as in `prisma service domain add staging.example.com --project acme-app --service hello-world --branch staging`. Without `--branch`, the commands still target production. The branch's primary URL and its **Visit** link then use the hostname. A branch that has a domain is no longer removed when its Git branch is deleted or when the branch is cleaned up for inactivity, and the Console's Git page says why it was kept. A workspace can register ten new domains per hour, and the limit of three domains per app stays. ([prisma-cli#354](https://github.com/prisma/prisma-cli/pull/354)) + +Attaching a domain now also asks you to prove that your workspace owns it. A domain that was attached before this change stays attached. The Console shows a TXT record to publish at `_prisma-verification.`, with a value specific to your workspace, beside the CNAME record, and a **Verify and connect** button checks both. The proof is kept, so you do not repeat it when you recreate the app or the branch. If your hostname is proxied through Cloudflare, the error now tells you what to do: set the record to DNS only first, wait until the domain shows **Active**, then switch it to Proxied with the TLS mode **Full (strict)**. + +A tool that deploys for you, such as a template installer, can send you straight to a domain's setup by adding `?setup=` to an app's Domains page, which opens the setup with the hostname filled in, or shows that the domain is already added. In the [REST API](https://www.prisma.io/docs/rest-api), a `POST /v1/services/{serviceId}/domains` request for a hostname that is not verified yet answers `422` with the code `domain-ownership-required` and the TXT record to publish as data, so a client can publish the record and retry. A workspace can also prove a whole domain once, such as `example.com` or `*.preview.example.com`, before it adds any hostname under it, with `POST /v1/workspaces/{workspaceId}/domain-ownerships`. These routes are marked experimental in the [OpenAPI spec](https://www.prisma.io/openapi.json) and may still change. + +
+ Add a domain in the Console + See the prisma 8.0.0-rc.28 release notes +
+ +## Address every part of your Prisma Compute app by name + +A Prisma Compute app is described by [Prisma Composer](https://www.prisma.io/docs/composer), the `composer` section of `prisma.config.ts` that the Console's setup pull request adds to a repository, and Composer names each part it deploys. The Prisma 8 command-line tool, `prisma`, runs those deploys for every app, including Prisma ORM 7 apps, and a workflow the Console set up pins its version. From `prisma@8.0.0-rc.28`, which ships Composer 0.35.0, each part's name is its full path starting with the app's name: `shop.api` is the service `api` of the app `shop`, and `shop.catalog.db` is the database `db` inside the app's `catalog` module. The part's environment variable names start with the same string, such as `COMPOSER_SHOP_CATALOG_DB`. The first deploy on this version renames an existing app's parts in place and replaces the connection strings and access keys Composer created, as described under "What you need to do". ([composer#384](https://github.com/prisma/composer/pull/384)) + +The new `prisma deploy list` prints every part an app has deployed on a stage, with its address, kind, platform id, and URL. A stage is a branch's deployment, and `--stage pr-42` names the same thing as the `pr-42` in an address below. `prisma@8.0.0-rc.30` renamed the flag to `--environment`, as the [November 4 entry](/changelog/2026-11-04) describes. Without `--stage` it lists production, and `--json` gives the same rows for scripts. ([composer#388](https://github.com/prisma/composer/pull/388)) + +```bash title="Terminal" +npx prisma deploy list --environment pr-42 # --stage pr-42 on prisma@8.0.0-rc.28 and rc.29 +``` + +Since `prisma@8.0.0-rc.29`, the `prisma` commands that act on a project, a service, a database, or a bucket accept an address in place of the id, written `@:
`, and leaving the environment out means production. So `prisma service logs @pr-42:shop.api` reads the logs of the `pr-42` preview, and `prisma postgres backup list @shop.catalog.db`, with no environment and no colon, lists production backups, without a lookup first. A command that deletes something takes the address itself as its confirmation, as in `prisma postgres delete @shop.catalog.db --confirm @shop.catalog.db`, and the question it asks says plainly when the target is production. The commands that take an address are `service show|delete|logs|open|version`, `postgres show|delete|usage|backup|connection`, `bucket delete|key`, and `project show|delete|transfer|link`, where a project's address is the app's name alone. ([prisma-cli#373](https://github.com/prisma/prisma-cli/pull/373)) + +Under `prisma dev`, which runs the app on your machine, a Next.js service now runs `next dev` instead of its production build, so your edits reload and its logs appear in your terminal, and a `node()` service can name its own dev command, as in `node({ dev: ["npm", "run", "dev"] })`. Each dev server gets the same environment a deployment would, on its own port. ([composer#381](https://github.com/prisma/composer/pull/381)) + +
+ Read about deploying with Composer + See the Composer 0.35.0 release notes +
+ +## On Postgres, a DateTime field in Prisma ORM 8 is a JavaScript Date again + +On Postgres, a field declared `DateTime` in a Prisma ORM 8 schema now reaches your code as a JavaScript `Date`, stored in a `timestamptz(3)` column. Until now it gave you a `Temporal.Instant`, which meant a polyfill on Node.js 22 and 24 and a conversion wherever a library expected a `Date`. The schema types `Date` and `Time`, not to be confused with the JavaScript class, now give you strings such as `"2024-02-29"` and `"09:30:00"`, and the new `Duration` gives you an ISO 8601 duration such as `"P1M"`. Every one of these types takes optional arguments: `DateTime(as: string, precision: 6)` reads the column as an ISO 8601 string with microseconds instead of a `Date`. To keep a field exactly as it was, rename its type to `TimestamptzTemporal`, `DateTemporal`, or `TimeTemporal`. If Prisma ORM 8 reads your Prisma 7 schema, a `DateTime` field is a JavaScript `Date` again, as it was in Prisma ORM 7. The stored contract changes with it, so run `prisma contract emit` and then `prisma db sign` against each database. SQLite, MySQL, and MongoDB keep their date types. The [schema reference](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax) lists each type and what it reads. ([#30847](https://github.com/prisma/orm/pull/30847)) + +```prisma title="prisma/schema.prisma" +model Event { + id Int @id @default(autoincrement()) + at DateTime // JavaScript Date, timestamptz(3) + day Date // "2024-02-29" + span Duration // "P1M" + exact TimestamptzTemporal // Temporal.Instant, as before +} +``` + +Prisma ORM 8 is still a release candidate, and this change arrived in `8.0.0-rc.22`. The explicit names came one release earlier, in `8.0.0-rc.21`, which also made every text date and time value ISO 8601 on every server, where it used to follow the Postgres session's time zone and date style. ([#30834](https://github.com/prisma/orm/pull/30834)) + +
+ Read the schema reference + See the rc.22 release notes +
+ +## What you need to do + +- **If you deploy to Prisma Compute, your first deploy with `prisma@8.0.0-rc.28`, the first release that ships Composer 0.35.0, or newer renames every part of the app and replaces its credentials.** Databases keep their rows, buckets keep their objects, and custom domains stay, but each database connection string and bucket access key that Composer created is replaced by a new one, which your services receive in the same deploy. Anything outside the app that copied an old connection string or access key needs the new one. Do not deploy that environment with an older `prisma` afterward, because the older version looks for the old names, recreates every resource, and loses the data. A workflow the Console set up pins the `prisma` version in its file under `.github/workflows/`, so this happens when you raise that pin. One case needs a manual step first: an app with a module or service named like the app itself, directly below the root. The [deploying guide](https://github.com/prisma/composer/blob/main/docs/guides/deploying.md) covers it under "Upgrading to addresses that start with the app name". ([composer#384](https://github.com/prisma/composer/pull/384)) +- **Before that deploy, set the entry file in `prisma.config.ts` and use full addresses in your code.** The entry file is the module that exports your app, usually `module.ts`. If your workflow or scripts run `prisma deploy module.ts` or `prisma dev module.ts`, that now fails with `CLI.INVALID_ARGUMENTS`, because the file name no longer goes on the command line. Write `composer: composer({ entry: "./module.ts", ... })` in `prisma.config.ts`, and use `--entry ` to override it for one run. Change `serviceOrigin("api")` to `serviceOrigin("shop.api")`, and run `prisma dev url shop.api` rather than `prisma dev url api`. ([composer#387](https://github.com/prisma/composer/pull/387)) +- **If you are on a Prisma ORM 8 release candidate older than `8.0.0-rc.20`**, first follow the steps in the [October 23 entry](/changelog/2026-10-23), which also covers the rc.18 step, then continue here. +- **If you are on a Prisma ORM 8 release candidate older than `8.0.0-rc.22`**, follow the upgrade guides for [rc.21](https://github.com/prisma/orm/blob/v8.0.0-rc.21/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.20-to-8.0.0-rc.21/) and [rc.22](https://github.com/prisma/orm/blob/v8.0.0-rc.22/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.21-to-8.0.0-rc.22/) in order. They tell you which date fields to rename and ship scripts for the rest. Each tells you when to run `prisma contract emit`, which regenerates the contract (the generated file that describes your schema, which the client and the migration commands read), and `prisma db sign --db "$DATABASE_URL"` against every database, which records that the database matches the new contract; in rc.22 the value-object step signs before the re-emit, as described below. Use library `8.0.0-rc.22` with the tool `prisma@8.0.0-rc.30`. The breaking changes below are the ones most likely to affect an app. `prisma skills sync` downloads the upgrade guides into your project as agent skills, and the guides for the rc.18 and rc.19 steps were repaired in rc.21. +- **If you install Prisma ORM 8 twice**, for example two versions of `@prisma/orm-postgres` in one project, every command and client now stops with `RUNTIME.MULTIPLE_ORM_COPIES` and names each copy. Install one version of every `@prisma/orm-*` package, and the `prisma` tool release that goes with it. ([#30883](https://github.com/prisma/orm/pull/30883)) +- **If a Prisma Compute app relies on its generated `prisma.build` address being found by search engines**, put it on a custom domain. Every generated host, including production, preview, and version addresses, now sends `X-Robots-Tag: noindex`, so search engines and AI crawlers stop indexing it. On a custom domain, your app controls indexing as before. +- **Prisma Postgres Early Access databases are deleted on November 1, 2026 at 00:00 UTC.** Follow the [migration guide](https://www.prisma.io/docs/postgres/migrate-from-ea-to-ga) today. +- **Accelerate is retired on December 1, 2026.** [Switch to a pooled connection or to the serverless driver](https://www.prisma.io/docs/postgres/database/switch-from-accelerate), or [keep your own database and connect to it without Accelerate](https://www.prisma.io/docs/accelerate/keep-your-database). + +## Breaking changes between Prisma ORM 8 release candidates + +These apply only if you upgrade from an earlier release candidate to `8.0.0-rc.21` or `8.0.0-rc.22`. The release notes for [rc.21](https://github.com/prisma/orm/releases/tag/v8.0.0-rc.21) and [rc.22](https://github.com/prisma/orm/releases/tag/v8.0.0-rc.22) list every change, including the ones for extension authors. After either upgrade, run `prisma contract emit` once, so that the versions of the Prisma ORM extension packages recorded in your contract match the ones you installed. + +- **`DateTime`, `Date`, and `Time` read different values on Postgres**, as described above. Rename a field to `TimestamptzTemporal`, `DateTemporal`, or `TimeTemporal` to keep it as it was. A schema you generate again from the database with `prisma contract infer` reads a `timestamptz` column as a `Date` and drops its microseconds, unless you change the field's type to `DateTime(as: string, precision: 6)`. ([#30847](https://github.com/prisma/orm/pull/30847)) +- **`Timestamptz`, `Timestamp`, and `Interval` are renamed.** They are now `TimestamptzTemporal`, `TimestampTemporal`, and `IntervalParts`, and the old names are errors. Renaming them is all you do; no re-emit and no migration is needed. ([#30834](https://github.com/prisma/orm/pull/30834)) +- **Text date and time values are ISO 8601 on every server.** A `TimestamptzString` field that read `2024-01-01 01:00:00+01` on a server in Berlin now reads `2024-01-01T00:00:00Z` everywhere, and a literal default on these types must be written in that form. The Postgres driver sets the session's `DateStyle` to ISO for you, including on a pool you pass in, so there is nothing to configure, but code that compared these strings to the old text needs the new one. ([#30834](https://github.com/prisma/orm/pull/30834)) +- **Field presets are removed.** A preset was a helper such as `id.uuidv4String()` or `temporal.createdAt()` that set a field's type and attributes in one call. Each is replaced by the type and attributes written out: `temporal.createdAt()` becomes `temporal.CreatedAt`, and `id.ulid()` becomes `Ulid @id @onCreate(ulid())`. The schema error names the exact rewrite, and the rewrite is all you do; no re-emit and no migration is needed. ([#30845](https://github.com/prisma/orm/pull/30845)) +- **A client member that returns a promise rejects instead of throwing at the call.** `query`, `execute`, `transaction`, and ORM calls on a closed client now report the failure through what they return, so a `try`/`catch` around a call without `await` no longer catches it. Add `await`. ([#30840](https://github.com/prisma/orm/pull/30840)) +- **Removing an enum value asks first**, like removing a model or a field, as described under "Prisma ORM" below. A script that runs without a terminal fails with `CLI.CONSENT_REQUIRED` until you answer with `--rename` or `--delete`. ([#30849](https://github.com/prisma/orm/pull/30849)) +- **Changing a value object is now a migration.** A value object is a composite type stored inside a row, such as an address with street and city fields. On Postgres, the next `prisma migration plan` also adds a check constraint for each value object column and for each column that tells model variants apart, and `prisma db migrate` fails on a row that does not fit. Run the rc.22 script, then `prisma db sign` against each database, then `prisma contract emit`, in that order, because the script rewrites the stored contract that signing checks. ([#30869](https://github.com/prisma/orm/pull/30869)) +- **The pgvector, PostGIS, and ParadeDB extension packages declare their Postgres extension, and `prisma contract emit` now writes each one's migration files** into its own folder under `migrations/`. Commit them, then run `prisma db migrate` on each database. ([#30902](https://github.com/prisma/orm/pull/30902)) +- **A Prisma 7 schema's `@default(now())` is filled by the client on create.** A create through Prisma ORM 8 now writes the current time in UTC, as Prisma 7's client did. Re-emit and commit the contract; no migration or `db sign` is needed. ([#30834](https://github.com/prisma/orm/pull/30834)) +- **`close()` now always closes the client.** It never closes a pool you passed in; end that yourself. ([#30833](https://github.com/prisma/orm/pull/30833)) +- **On MongoDB, only code that builds the query builder, raw API, or ORM objects itself changes.** Those now take a context from `mongoStatic({ contract })` instead of `{ contract }`, `mongoContract(schemaPath, options)` requires `options.target`, and identical or redundant indexes in one collection are merged into one. An app that calls `mongo({ contract, url })` sees no difference from the driver change, but the contract rules also tightened: rc.21 refuses an optional or list discriminator, an enum a value object does not declare, and duplicate indexes, and the merged indexes change the stored contract, so run `prisma contract emit` and `prisma db sign` after upgrading. ([#30865](https://github.com/prisma/orm/pull/30865), [#30846](https://github.com/prisma/orm/pull/30846), [#30894](https://github.com/prisma/orm/pull/30894)) + +## Prisma ORM + +When your schema removes an enum value, or changes the value it stores, `migration plan` and `db update` on Postgres and SQLite now ask what the change means and rewrite the rows that hold the old value. `prisma migration plan --rename Status.ARCHIVED:Status.RETIRED` changes the stored value in every column and list that holds it, and `--delete Status.ARCHIVED` sets it to `NULL` in optional columns and takes it out of lists. On a required column that still holds the value, the apply stops before changing anything and says how to keep the data. Before, Postgres failed at apply when a row held the old value, and SQLite planned nothing. Native Postgres enums declared with `pg.enum(...)` are unchanged. ([docs](https://www.prisma.io/docs/cli/migration-plan#renames-and-data-loss), [#30849](https://github.com/prisma/orm/pull/30849)) + +MySQL has its first public packages, `@prisma/orm-mysql` and `@prisma/orm-target-mysql`, as an early preview. They can emit a contract, and on MySQL 8.4 plan and apply migrations that create and drop tables, columns, indexes, unique constraints, and foreign keys, and, since `8.0.0-rc.22`, read with the ORM and the SQL query builder, including nested and ordered includes. Other schema changes and writes are refused with a message that says they are not supported on MySQL yet. The [supported databases](https://www.prisma.io/docs/orm/supported-databases) page says what works today. ([#30841](https://github.com/prisma/orm/pull/30841), [#30863](https://github.com/prisma/orm/pull/30863)) + +The two releases also add the following: + +- **Declare the Postgres extensions your schema needs.** `extension pg_trgm {}` in a schema file, or `extension('pg_trgm')` in TypeScript, makes `prisma db verify` check that the extension is installed and makes a migration create it. When Prisma ORM 8 reads a Prisma 7 schema, it reads the `extensions` list of its datasource too, so a Prisma 7 database that uses pgvector, PostGIS, or ParadeDB can now be adopted with `prisma contract emit` and `prisma db sign`. ([docs](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#postgresql-extensions), [#30902](https://github.com/prisma/orm/pull/30902)) +- **Read every Postgres `@db.*` type from a Prisma 7 schema.** A new package, `@prisma/orm-postgres-contrib`, adds the case-insensitive `citext.Citext` type, and Postgres gains `Xml`, `Oid`, and `Money`. With them, Prisma ORM 8 reads `@db.Citext`, `@db.Bit`, `@db.VarBit`, `@db.Xml`, `@db.Oid`, and `@db.Money` from a Prisma 7 schema. A `money` column reads and writes the same value in any locale. ([#30904](https://github.com/prisma/orm/pull/30904), [#30900](https://github.com/prisma/orm/pull/30900)) +- **Call `connect()` more than once.** `connect()` without options on a client is now safe to call again: it waits for a connection in progress, or returns the connection the client already uses. ([#30899](https://github.com/prisma/orm/pull/30899)) +- **Pick the right type for a generated id.** Every SQL target has a type alias for each generated identifier's column, such as `Ulid`, `Nanoid`, and `Cuid2`, so `id Ulid @id @onCreate(ulid())` declares a column of the right length. SQLite gains `sql.Char(n)`. ([#30845](https://github.com/prisma/orm/pull/30845)) +- **Read a `timestamp` column as a `Date` or an `Instant`.** `TimestampJsDate(p?)` and `TimestampInstant(p?)` read a `timestamp` column as UTC, and `IntervalString(p?)` reads an `interval` as an ISO 8601 duration. ([#30834](https://github.com/prisma/orm/pull/30834)) +- **Find extensions on npm.** Prisma's extension packages carry the npm keyword `prisma-orm-extension`, and the [extensions](https://www.prisma.io/docs/orm/extensions) page tells community authors to use the same keyword, so one search finds them all. ([#30892](https://github.com/prisma/orm/pull/30892)) + +## Prisma Compute + +Creating a branch no longer copies the default branch's Object Storage buckets into the new branch. A new branch starts with no buckets, whether you create it from the Console, the REST API, or the Prisma MCP server. If your workflow relied on those copies, create the buckets yourself, in the Console or with `prisma bucket create`. + +Repository search when you connect GitHub now covers your whole list of repositories, up to 1,000, instead of the first 100, so you no longer click **Load more** to find one. + +## Prisma Postgres + +Databases created through the Vercel Marketplace integration now also get a `DATABASE_URL_POOLED` variable, pointing at the connection pooler, beside the direct `DATABASE_URL`. Until now the [Vercel guide](https://www.prisma.io/docs/guides/postgres/vercel) told you to create the pooled string in the Console and add it by hand. A database that already exists gets the variable when you rotate its credentials with **Rotate Secrets** in the Vercel integration's settings. + +## Prisma Console + +Signing out of the Console now ends every session on every device, including the session at `auth.prisma.io`. Before, only the browser you signed out of lost its session. + +## Prisma MCP server + +ChatGPT, and other MCP clients that register themselves with the Prisma MCP server, no longer stop working 30 days after setup with `Invalid Client ID`. If yours did, reconnect it, and it keeps working without being set up again. A connection that stays unused for 30 days still asks you to sign in again. + +## Docs and website + +- [Deploy to Vercel](https://www.prisma.io/docs/guides/deployment/vercel) takes a Next.js app on Prisma ORM 8 from repository to Vercel in five steps, and explains why a server component that reads rows at build time shows stale data unless the page sets `export const dynamic = "force-dynamic"`. +- [Money and decimals](https://www.prisma.io/docs/orm/data-modeling/money) says when to store integer cents, `Numeric(p, s)`, or `Decimal`, and why decimal fields are strings in both directions. +- [Types for your code](https://www.prisma.io/docs/orm/fundamentals/types) lists the Prisma ORM 8 types for typing your own functions, with each Prisma ORM 7 type, such as `Prisma.UserWhereInput`, beside its replacement. +- Three new extension pages take you from install to a working query: [PostGIS](https://www.prisma.io/docs/orm/extensions/postgis), [ParadeDB](https://www.prisma.io/docs/orm/extensions/paradedb), and [arktype-json](https://www.prisma.io/docs/orm/extensions/arktype-json). +- [Backups](https://www.prisma.io/docs/postgres/database/backups) now explains where a restore goes: into a new database in the same project, which gets a new connection string, or in place, which overwrites the database, closes open connections, and keeps the connection strings. +- The [Prisma Postgres error reference](https://www.prisma.io/docs/postgres/error-reference) explains each `Failed to identify your database` error, and the [FAQ](https://www.prisma.io/docs/postgres/faq) answers how to delete a database created through Vercel and why custom database roles cannot be created. +- [Free PostgreSQL hosting](/postgres/free-postgresql-hosting) explains what the free Prisma Postgres database includes and how a temporary database from `create-db` differs from one you claim. +- The CLI reference now has exit codes and error codes for [`orm init`](https://www.prisma.io/docs/cli/orm-init#exit-codes), `migration ref`, and `contract emit --json`, so a CI step can branch on them. + +## Fixes + +### Prisma ORM 8 + +- On SQLite, a query with parameters in a join or derived table and also in `WHERE`, or in `GROUP BY` and also in `HAVING` or `ORDER BY`, bound its values to the wrong placeholders and returned wrong rows. Each value now binds to its own placeholder. ([#30853](https://github.com/prisma/orm/pull/30853)) +- If the database says it is at a migration that no longer exists in your migrations folder, for example because the migration was deleted or planned again, `prisma db migrate` now explains that and offers two ways to recover. Before, it suggested commands the CLI refuses. Neither recovery resets the database. ([#30866](https://github.com/prisma/orm/pull/30866)) +- A lost Postgres connection, such as `57P01` or `EPIPE`, is now reported as a connection error, and a failed connection attempt is reported on every later use instead of hanging. A SQLite file that cannot be opened is now a connection error too, not a query error. ([#30833](https://github.com/prisma/orm/pull/30833)) +- The upgrade guides and scripts for rc.18 to rc.19 and rc.19 to rc.20 now work on real projects: the scripts skip hidden directories such as `.next/`, and both guides say how to recover a database that is behind on migrations. ([#30855](https://github.com/prisma/orm/pull/30855)) +- On Postgres, the `now` generator of a timestamp column rounds the time down to the column's precision, so the value a create returns is the value the database stores. ([#30847](https://github.com/prisma/orm/pull/30847)) +- `Temporal` fields were typed `any` in a project without a polyfill's global declarations. They are now typed correctly without one. ([#30834](https://github.com/prisma/orm/pull/30834)) +- A schema with a field whose type does not resolve now reports that field's own error, instead of an unrelated relation error. On SQLite, an unknown bare type such as `Ulid` suggests `sql.Ulid`. ([#30845](https://github.com/prisma/orm/pull/30845)) +- The error for a Prisma 7 `@db.*` attribute in a Prisma ORM 8 schema suggests the type Prisma ORM 8 renamed it to, such as `String` for `@db.Text`. ([#30909](https://github.com/prisma/orm/pull/30909)) + +### Prisma Console + +- Opening a Console page from a link no longer sometimes shows `No result found for routeId` on the first load. + +## Guides and articles + +- [How we moved Prisma's control plane to Prisma Postgres without downtime](https://www.prisma.io/blog/moving-prismas-control-plane-to-prisma-postgres): 83 tables and 74 GB moved from Amazon RDS with logical replication, with a rollback kept open for a week. + +--- + +*Need help applying these changes in production? [Prisma Enterprise Support](/enterprise) can help with schema design, performance, security, and compliance.* diff --git a/apps/site/content/changelog/2026-11-04.mdx b/apps/site/content/changelog/2026-11-04.mdx new file mode 100644 index 00000000000..337b3ebf9c8 --- /dev/null +++ b/apps/site/content/changelog/2026-11-04.mdx @@ -0,0 +1,95 @@ +--- +title: "Build and deploy a Prisma app from one ChatGPT prompt with the official Prisma plugin" +date: "2026-11-04" +version: "2026-11-04" +slug: "2026-11-04" +headline: "Build and deploy a Prisma app from one ChatGPT prompt with the official Prisma plugin" +tags: + - "Prisma" + - "Prisma Compute" + - "Prisma Postgres" + - "Prisma ORM" + - "Prisma MCP server" +canonical: "/changelog#log2026-11-04" +metaDescription: "The official Prisma plugin for ChatGPT connects ChatGPT and Codex to Prisma ORM, Prisma Postgres, and Prisma Compute, so one prompt can build an app, set up its database, and deploy it. Also new: prisma deploy --environment replaces --stage, and prisma dev can run a second local copy of your app." +share: + active: true + content: "Look at this page: " +--- +**The official Prisma plugin for ChatGPT is out. It connects ChatGPT and Codex to Prisma ORM, Prisma Postgres, and Prisma Compute, so one prompt can build an app, create and connect its database, and deploy it.** Prisma ORM 8 is still a release candidate, and `prisma@8.0.0-rc.30`, released on November 3, is its command-line tool, which also deploys apps to Prisma Compute. Prisma Composer is the `composer` section of `prisma.config.ts` that describes a Prisma Compute app's services and databases. In this release, the place a Composer app runs is called an environment: `prisma deploy --environment staging` replaces `--stage`, and `prisma dev --environment test` runs a second, separate copy of your app on your machine. Cloning a Prisma Postgres database no longer blocks connections to the source while the clone runs. + +If your `package.json` pins `prisma@7`, nothing in this entry changes your commands, but a script that installs `prisma@latest` gets Prisma 8. If you run `prisma deploy` yourself with `--stage`, replace it, as described under "What you need to do". Accelerate is retired on **December 1, 2026**, and if your connection string does not contain `accelerate.prisma-data.net`, that does not affect you. + +## Ask ChatGPT to build, connect, and deploy your app + +Until now, building an app with ChatGPT meant switching between the chat, a database dashboard, and a terminal to connect the pieces. The [Prisma plugin for ChatGPT](https://pris.ly/gpt-plugin) gives ChatGPT and Codex the context they need to write the data layer with Prisma ORM, create a Prisma Postgres database and connect the app to it, and deploy the result to Prisma Compute, from one conversation. + +To try it, install the plugin in ChatGPT, then ask ChatGPT, or [Codex](https://chatgpt.com/codex), OpenAI's coding agent, which the plugin also connects: + +```text title="Prompt" +Build me a workout tracker using Prisma ORM and Prisma Postgres, then deploy it to Prisma Compute. +``` + +If you already connect ChatGPT to Prisma through the [Prisma MCP server](https://www.prisma.io/docs/ai/tools/mcp-server) by hand, that setup keeps working, and the [ChatGPT guide](https://www.prisma.io/docs/ai/tools/chatgpt) still describes it. + +
+ Install the Prisma plugin + Read the launch post +
+ +## Run a second local copy of your app with prisma dev --environment + +In the Prisma 8 command-line tool, `prisma dev` runs your whole [Prisma Composer](https://www.prisma.io/docs/composer) app on your machine, services and databases included, with no Prisma account. The Prisma ORM 7 command of the same name, which starts a local Prisma Postgres database, is unchanged in version 7. Until now you could run only one local copy of an app, so a test that needed a clean database meant wiping the copy you work in with `--fresh`. Since `prisma@8.0.0-rc.30`, each environment name gets its own complete local copy, with its own database, storage, and ports, and the copy you get by default is named `dev`. The commands below act on whichever copy you name, while `dev` keeps running. `--fresh` wipes the copy you name before starting it and leaves the other copies alone. ([composer#392](https://github.com/prisma/composer/pull/392)) + +```bash title="Terminal" +npx prisma dev --detach # the environment dev +npx prisma dev --environment test --fresh --detach # a second, clean copy beside it +npx prisma dev url shop.api --environment test +npx prisma dev stop --environment test +``` + +The same word now names a deployed environment too. `prisma deploy --environment staging` deploys there, `prisma deploy` on its own deploys production, and `prisma deploy list --environment staging` lists what is deployed. If a script of yours tears down an environment with Composer's `destroy()` function, it must now name the environment, and a call without a name fails instead of destroying production. ([composer#390](https://github.com/prisma/composer/pull/390)) + +`prisma dev` also no longer makes up a value for a secret you have not set. Before, an unset secret such as an API key got a placeholder string, so a service could not tell whether it had a real key. Now a secret comes only from the shell you run `prisma dev` in, or from a `.env` file that `prisma.config.ts` loads. If a secret the service requires is missing, `prisma dev` stops and the error names the variable and the service. If the service's input declares the secret optional, as in `'apiKey?': secretString()`, it is left unset, so a feature that depends on it stays off. The [service input](https://www.prisma.io/docs/composer/service-input) page explains that an unset variable leaves its field out of the input, and the service's schema decides whether that is allowed. ([composer#382](https://github.com/prisma/composer/pull/382)) + +
+ Read about local development + See the Composer 0.36.0 release notes +
+ +## What you need to do + +- **If you run `prisma deploy --stage` in a script or a workflow**, change it to `prisma deploy --environment` when you move to `prisma@8.0.0-rc.30`. On that version, `--stage` fails with `CLI.COMMAND_MOVED` and names the replacement. Upgrade `@prisma/composer-prisma-cloud` to 0.36.0 in the same step: `prisma@8.0.0-rc.30` ships Composer 0.36.0, and the extension and the tool that runs the deploy must be the same Composer version, or `prisma deploy`, `destroy()`, and `prisma dev` refuse with `DEPS.EXTENSION_INCOMPATIBLE` before they change anything. A workflow that the Console set up for you pins its `prisma` version, and for now keep that pin below rc.30: the workflow deploys through `prisma/cloud-deploy-action`, which still passes `--stage` for every branch other than the default one, so raising the pin breaks preview and staging deploys until the action sends `--environment`. A production deploy from the default branch passes no flag and is not affected. In a script that calls Composer's `destroy()`, `destroy({ target: { kind: 'stage', stage: 'staging' }, config })` becomes `destroy({ environment: 'staging', config })`, and production is `destroy({ environment: 'production', config })`. Such a script imports `destroy()` from the project's own `@prisma/composer`, so upgrade that package to 0.36.0 with the extension, whether or not the script used `--stage`. One install problem is open: `@prisma/composer-prisma-cloud@0.36.0` still declares a peer dependency on `@prisma/orm-postgres@8.0.0-rc.20`, so with npm an install beside `8.0.0-rc.22` stops with `ERESOLVE` until you pass `--legacy-peer-deps` ([composer#413](https://github.com/prisma/composer/issues/413)). ([composer#390](https://github.com/prisma/composer/pull/390)) +- **If `prisma dev` worked for you without every secret set**, set each secret before you upgrade, either by exporting it in the shell you run `prisma dev` from, or by installing `dotenv` and adding `import "dotenv/config";` at the top of `prisma.config.ts` so it loads your `.env` file. The error names each missing variable and the service that needs it. `prisma deploy` reads the same `prisma.config.ts`, so a value in that `.env` file reaches a deploy too, and the first deploy to a new environment copies any secret the environment does not have yet from the shell the deploy runs in, as the [deploy guide](https://www.prisma.io/docs/composer/deploying) explains. Keep a development-only value, such as a test API key, out of the `.env` file that `prisma.config.ts` loads, or set it in the shell only, because a deploy run from that folder would seed it into the environment. ([composer#382](https://github.com/prisma/composer/pull/382)) +- **If you are on Prisma ORM 7**, nothing in this entry needs a change in your app. The `prisma@8.0.0-rc.30` release is the Prisma 8 command-line tool; your project stays on version 7 as long as its `package.json` asks for it. Check any script or CI job that installs `prisma@latest` and change it to `prisma@7`, because `latest` is Prisma ORM 8. +- **Accelerate is retired on December 1, 2026.** If your app connects through a URL that starts with `prisma+postgres://accelerate.prisma-data.net`, [switch to a pooled connection or to the serverless driver](https://www.prisma.io/docs/postgres/database/switch-from-accelerate) before then. If you use Accelerate with your own database, [keep your database and connect to it without Accelerate](https://www.prisma.io/docs/accelerate/keep-your-database). + +## Prisma Compute + +The Console can now open its setup pull request on a repository that uses Vite 7 or a non-beta release of drizzle-kit. Before, the setup stopped on an npm dependency conflict and no pull request was opened. + +The Console's setup steps are now right for the version of Prisma ORM a repository uses. A Prisma ORM 7 repository no longer reads that it must move to Prisma ORM 8, because Prisma Compute runs Prisma ORM 7 apps. Instead it gets the steps from the [side-by-side guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql): the Prisma 8 command-line tool is installed as `prisma` to run deploys, your Prisma ORM 7 client keeps running as it is, and its own tool becomes `prisma7`. This is the intended path for a Prisma ORM 7 app on Prisma Compute. A Prisma ORM 8 repository is no longer told to run `prisma migrate dev`, which is a Prisma ORM 7 command. + +A GitHub deploy no longer shows **Deploying** forever when the workflow finished green but never deployed anything. The build is now marked failed with the reason, for example that the workflow's `permissions` block lacks `id-token: write`, which the deploy action needs to get its credential. A copy of a template that was stuck on **Deploying** after its first CI run now recovers when you re-run the workflow. + +## Prisma Postgres + +Cloning a database no longer blocks connections to the database you clone from. Before, the source refused new connections for the few minutes the clone took. + +## Prisma Console + +The page that asks you to allow an app to use your Prisma account, at `auth.prisma.io/authorize`, now matches the sign-in page. It shows the app's icon, which account you are signed in as, with a way to switch, one row per permission with a plain explanation, and the workspace the app will use. + +## Docs and website + +- Every Prisma Compute app template now has its own page under [/apps](/apps), with the running app in a browser frame, what it does, the three deploy steps, and a **Deploy on Prisma** button, so you can share a template by link. The first is [Room Booking](/apps/room-booking-prisma-template), a community template. +- The [Prisma Postgres overview](https://www.prisma.io/docs/postgres) gains a path for a project that already has a Prisma schema: create a database with `npx create-db@latest --env .env` and apply the schema you have. +- The [Prisma Postgres guides](/postgres/guides) directory gains a page on high availability. + +## Guides and articles + +- [One ChatGPT plugin to deploy it all](https://www.prisma.io/blog/one-chatgpt-plugin-to-deploy-it-all): the official Prisma plugin for ChatGPT connects ChatGPT and Codex to Prisma ORM, Prisma Postgres, and Prisma Compute, so you can build, set up the database, and deploy from one prompt. + +--- + +*Need help applying these changes in production? [Prisma Enterprise Support](/enterprise) can help with schema design, performance, security, and compliance.* diff --git a/apps/site/src/app/changelog/page.tsx b/apps/site/src/app/changelog/page.tsx index f4814626354..b9045abd8f7 100644 --- a/apps/site/src/app/changelog/page.tsx +++ b/apps/site/src/app/changelog/page.tsx @@ -3,7 +3,7 @@ import { ChangelogFeed } from "@/components/sections/changelog-feed"; import { ChangelogHero } from "@/components/sections/changelog-hero"; import { CtaBurst } from "@/components/sections/cta-burst"; import { extractPreview, getChangelogEntries } from "@/lib/changelog"; -import { categoryForTags, isHighlight, type ChangelogEntry } from "@/lib/changelog-meta"; +import { categoriesForTags, isHighlight, type ChangelogEntry } from "@/lib/changelog-meta"; export const metadata = createPageMetadata({ title: "Changelog", @@ -16,16 +16,18 @@ export const metadata = createPageMetadata({ // /changelog — the redesign (spectral hero, product-area filter, colour-coded // timeline) driven by the live changelog content so it keeps auto-updating. // Entries come from the same source as the per-entry pages and the AI/GEO feed; -// each entry's product area is derived from its tags (see categoryForTags), and +// each entry's product areas are derived from its tags (see categoriesForTags), and // the feed is a client component, so we build the list here and pass it down. export default function ChangelogPage() { const entries: ChangelogEntry[] = getChangelogEntries().map((entry) => { const title = entry.frontmatter.headline ?? entry.frontmatter.title; + const categories = categoriesForTags(entry.frontmatter.tags); return { date: entry.frontmatter.date, title, description: entry.frontmatter.metaDescription ?? extractPreview(entry.content) ?? "", - category: categoryForTags(entry.frontmatter.tags), + category: categories[0], + categories, tags: entry.frontmatter.tags?.slice(0, 3) ?? [], highlight: isHighlight(title), href: `/changelog/${entry.slug}`, diff --git a/apps/site/src/components/sections/changelog-feed.tsx b/apps/site/src/components/sections/changelog-feed.tsx index 7a84e91c893..2ef52a2bce0 100644 --- a/apps/site/src/components/sections/changelog-feed.tsx +++ b/apps/site/src/components/sections/changelog-feed.tsx @@ -13,9 +13,15 @@ import { cn } from "@/lib/utils"; // The feed: a sticky category filter over a colour-coded release timeline. // One client component because the tabs and the list share a single piece of -// filter state — the same call data/blog-browser makes. Twelve entries is far -// too few to debounce or round-trip, so filtering is a plain array filter in -// the client and the state stays out of the URL (no deep links to share yet). +// filter state — the same call data/blog-browser makes. A few dozen entries is +// far too few to debounce or round-trip, so filtering is a plain array filter +// in the client and the state stays out of the URL (no deep links to share yet). +// +// The filter is multi-select: each pill toggles an area, and an entry shows +// when it belongs to any selected area. An entry belongs to every area its +// tags name (a Compute launch backed by Prisma Postgres is under both), so +// picking Postgres lists everything about Postgres, not only entries whose +// first tag is Postgres. No selection means every entry. // // The timeline is the redesign's answer to the live changelog's flat numbered // list: a vertical spine on desktop with a category-coloured node per entry, @@ -30,25 +36,35 @@ const FMT = new Intl.DateTimeFormat("en-US", { timeZone: "UTC", }); -type Filter = ChangelogCategory | "all"; - export function ChangelogFeed({ entries: allEntries }: { entries: ChangelogEntry[] }) { - const [filter, setFilter] = useState("all"); + // The selected areas. Empty means no filter, which the "All updates" pill + // both shows and restores. + const [selected, setSelected] = useState>(new Set()); + + const toggle = (id: ChangelogCategory) => + setSelected((prev) => { + const next = new Set(prev); + if (!next.delete(id)) next.add(id); + return next; + }); // Counts per category — totals over the whole feed that never change with the - // active filter. + // active filter. An entry counts towards every area it belongs to. const COUNTS = useMemo( () => CATEGORY_ORDER.reduce>((acc, id) => { - acc[id] = allEntries.filter((e) => e.category === id).length; + acc[id] = allEntries.filter((e) => e.categories.includes(id)).length; return acc; }, {}), [allEntries], ); const entries = useMemo( - () => (filter === "all" ? allEntries : allEntries.filter((e) => e.category === filter)), - [filter, allEntries], + () => + selected.size === 0 + ? allEntries + : allEntries.filter((e) => e.categories.some((id) => selected.has(id))), + [selected, allEntries], ); return ( @@ -60,8 +76,8 @@ export function ChangelogFeed({ entries: allEntries }: { entries: ChangelogEntry
setFilter("all")} + active={selected.size === 0} + onClick={() => setSelected(new Set())} label="All updates" count={allEntries.length} /> @@ -71,8 +87,8 @@ export function ChangelogFeed({ entries: allEntries }: { entries: ChangelogEntry {CATEGORY_ORDER.filter((id) => (COUNTS[id] ?? 0) > 0).map((id) => ( setFilter(id)} + active={selected.has(id)} + onClick={() => toggle(id)} label={CATEGORY_META[id].label} count={COUNTS[id] ?? 0} dot={CATEGORY_META[id].dot} @@ -233,13 +249,21 @@ function EntryCard({ />
- {/* meta row: category chip + date (date shows here on mobile, where the - rail is hidden) */} + {/* meta row: one chip per product area the entry belongs to, then the + date (which shows here on mobile, where the rail is hidden) */}
- - - {meta.label} - + {entry.categories.map((id) => ( + + + {CATEGORY_META[id].label} + + ))} {entry.highlight && ( Highlight )} diff --git a/apps/site/src/lib/changelog-meta.test.ts b/apps/site/src/lib/changelog-meta.test.ts new file mode 100644 index 00000000000..5ff19c07f50 --- /dev/null +++ b/apps/site/src/lib/changelog-meta.test.ts @@ -0,0 +1,30 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { categoriesForTags, categoryForTags } from "./changelog-meta"; + +test("an entry belongs to every product area its tags name", () => { + assert.deepEqual(categoriesForTags(["Prisma", "Prisma Compute", "Prisma Postgres"]), [ + "compute", + "postgres", + ]); + assert.deepEqual(categoriesForTags(["Prisma ORM", "Prisma Postgres", "Prisma Studio"]), [ + "studio", + "postgres", + "orm", + ]); +}); + +test("the colouring area is the most specific one", () => { + assert.equal(categoryForTags(["Prisma ORM", "Prisma Postgres"]), "postgres"); + assert.equal(categoryForTags(["Prisma Postgres", "Prisma Compute"]), "compute"); + assert.equal(categoryForTags(["Accelerate", "Pulse"]), "postgres"); +}); + +test("tags that name no product are platform-wide", () => { + assert.deepEqual(categoriesForTags(["Prisma", "REST API"]), ["platform"]); + // "Platform" contains "orm"; it must not read as an ORM tag. + assert.deepEqual(categoriesForTags(["Prisma Compute", "Platform"]), ["compute"]); + assert.deepEqual(categoriesForTags(["Platform"]), ["platform"]); + assert.deepEqual(categoriesForTags(), ["platform"]); + assert.equal(categoryForTags(["MCP"]), "platform"); +}); diff --git a/apps/site/src/lib/changelog-meta.ts b/apps/site/src/lib/changelog-meta.ts index e36dfff6fa6..4d9c6b270a6 100644 --- a/apps/site/src/lib/changelog-meta.ts +++ b/apps/site/src/lib/changelog-meta.ts @@ -11,7 +11,11 @@ export type ChangelogEntry = { date: string; title: string; description: string; + /** The area that colours the entry: the first of `categories`. */ category: ChangelogCategory; + /** Every product area the entry's tags name. An entry about a Compute feature + * backed by Prisma Postgres is in both, so both filters list it. */ + categories: ChangelogCategory[]; /** Short labels shown as pills under the entry. */ tags: string[]; /** Big launches get a featured treatment (larger card, accent). */ @@ -69,17 +73,29 @@ export const CATEGORY_ORDER: ChangelogCategory[] = [ "platform", ]; -// Derive a product area from an entry's tags. Entries carry free-form tags -// (e.g. "Prisma ORM", "Prisma Postgres", "Pulse"), not a single category, so we -// map the most specific product match first and fall back to platform-wide. -// Pulse/Accelerate are data-platform products, grouped under Postgres. +// Derive product areas from an entry's tags. Entries carry free-form tags +// (e.g. "Prisma ORM", "Prisma Postgres", "Pulse"), not a single category, and +// one entry often spans several products, so every area a tag names is kept. +// Pulse/Accelerate are data-platform products, grouped under Postgres. The +// result is ordered most specific first, and that first area colours the entry. +// An entry whose tags name no product is platform-wide. +const AREA_PATTERNS: [ChangelogCategory, RegExp][] = [ + ["studio", /studio/], + ["compute", /compute|composer/], + ["postgres", /postgres|accelerate|pulse|data platform/], + ["orm", /\borm\b|client|migrate|schema/], +]; + +export function categoriesForTags(tags: string[] = []): ChangelogCategory[] { + const areas = AREA_PATTERNS.filter(([, pattern]) => + tags.some((tag) => pattern.test(tag.toLowerCase())), + ).map(([area]) => area); + return areas.length > 0 ? areas : ["platform"]; +} + +/** The one area that colours an entry: the most specific of its areas. */ export function categoryForTags(tags: string[] = []): ChangelogCategory { - const haystack = tags.join(" ").toLowerCase(); - if (/studio/.test(haystack)) return "studio"; - if (/compute/.test(haystack)) return "compute"; - if (/postgres|accelerate|pulse|data platform/.test(haystack)) return "postgres"; - if (/orm|client|migrate|schema/.test(haystack)) return "orm"; - return "platform"; + return categoriesForTags(tags)[0]; } // Big launches get the featured treatment — reserved for genuine GA / beta /