Releases: prisma/orm
Release list
v8.0.0-rc.8
v8.0.0-rc.8
The toolchain releases against @prisma/cli-engine@0.3.0, which now takes the Management API SDK as a peer dependency, and migration plan no longer plans silently from an empty database when migrations already exist.
The upgrade recipe for this hop: the user recipe.
Breaking changes
- The engine peer moves to
@prisma/cli-engine@0.3.0—@prisma/orm-toolchaindeclares the unified CLI's engine as an exact peer, and this release peers 0.3.0 (up from 0.2.3). The engine's change:@prisma/management-api-sdkmoves from a regular dependency to a peer dependency (^1.55.0), supplied by theprismaCLI shell at runtime. Installs assembled by the unifiedprismaCLI resolve one engine as before; a host that pins the engine itself must move to 0.3.0 and, if it runs the engine outside the CLI shell, install the SDK itself. (prisma/prisma-cli#236)
Features
- The
prisma-8skill, auto-installed into every project byprisma init, now teaches agents the migration system's real model — plan-from-state with explicit baselines, not a linear chain — so agents stop producing full-create plans against real databases. (#30123)
Fixes
migration planrefuses to plan from an empty database when the project already has migrations on disk, instead of silently producing a full-create package that fails against any real database. A structured error explains the situation; planning from baseline remains available as an explicit opt-in. (#30122)- Structured errors'
docsUrllinks now point atdocs.prisma.io/docs/orm/v8/...instead of the pre-RCorm/next/...path. (#30126) - The language server now canonicalizes Windows file URIs, so schema files configured with Windows paths (
D:\project\next.prisma) are recognized as part of the project. (#30121) - The
devdist-tag no longer goes stale after a release: a release push tomainalso publishes a-dev.1build of the new base, so@devinstalls always resolve against the current release's engine pins. (#30125)
v8.0.0-rc.7
v8.0.0-rc.7
ORM collection pagination renames to limit/offset, and the toolchain releases against @prisma/cli-engine@0.2.3, the engine whose config loader ships the prisma init scaffold fixes from the unified CLI's rc line.
The upgrade recipe for this hop: the user recipe.
Breaking changes
-
ORM pagination is
limit/offset, nottake/skip—.take(n)and.skip(n)are renamed to.limit(n)and.offset(n)on SQL and Mongo ORM collections, including relation refinements and grouped SQL collections; the old names are removed. Semantics are unchanged. Mongo's lower-level query builder keeps.skip(n)— it names the native$skippipeline stage, not the collection API. (#30112)Before:
await db.orm.User.orderBy((u) => u.id.asc()).skip(10).take(10).all();
After:
await db.orm.User.orderBy((u) => u.id.asc()).offset(10).limit(10).all();
-
The engine peer moves to
@prisma/cli-engine@0.2.3—@prisma/orm-toolchaindeclares the unified CLI's engine as an exact peer, and this release peers 0.2.3 (up from 0.2.2). Installs assembled by the unifiedprismaCLI resolve one engine as before; a host that pins the engine itself must move to 0.2.3. (prisma/prisma-cli#225, prisma/prisma-cli#227)
v8.0.0-rc.6
v8.0.0-rc.6
PostgreSQL temporal columns move from Date to explicit Temporal-or-text representations, the prisma-8 agent skill ships inside the ORM packages a project installs, prisma orm init hands agent-skills setup to the family-level prisma init, and the toolchain releases against @prisma/cli-engine@0.2.2 — the engine that evaluates prisma.config.ts correctly under pnpm symlink layouts.
The upgrade recipe for this hop: the user recipe.
Breaking changes
-
PostgreSQL temporal columns read as
Temporalvalues or text, neverDate— each ofdate,timestamp(p),timestamptz(p)andtime(p)now has two representation-explicit codecs: aTemporal-backed one (the bare PSL spellingsDate,Timestamp,Timestamptz,Timeselect it) and a text one (DateString,TimestampString,TimestamptzString,TimeString). The previous codecs (pg/date@1,pg/timestamp@1,pg/timestamptz@1,pg/time@1,sql/timestamp@1/field.timestamp()) are removed with no aliases. Pick a representation per column, re-emit every contract, and provide a globalTemporalimplementation (e.g.import 'temporal-polyfill/full/global') wherever a Temporal-backed column is read. See the migration recipe. (#30073)Before:
occurredAt Timestamptz // read as DateAfter (read as
Temporal.Instant):occurredAt Timestamptz
Or, to keep PostgreSQL's text unchanged:
occurredAt TimestamptzString
-
prisma orm initno longer installs agent skills — the GitHub fetch (npx skills add) is removed and nothing replaces it insideorm init: agent-skills setup belongs to the family-levelprisma initcommand, which init's next-steps now point to. The--skip-skillsflag is removed with the behavior it opted out of, and the skill-install failure exit (code 6) is retired. Scaffolding is otherwise unchanged. (#30097) -
The engine peer moves to
@prisma/cli-engine@0.2.2—@prisma/orm-toolchaindeclares the unified CLI's engine as an exact peer, and this release peers 0.2.2 (up from 0.2.0). Installs assembled by the unifiedprismaCLI resolve one engine as before; a host that pins the engine itself must move to 0.2.2. The new engine evaluatesprisma.config.tsthrough pnpm symlink layouts that are not realpath'd (prisma/prisma-cli#222) and exports its CI detector (prisma/prisma-cli#224).
Features
- The prisma-8 skill travels in the npm tarballs —
skills/prisma-8/ships inside@prisma/orm-postgres,@prisma/orm-sqlite, and@prisma/orm-mongo, stamped with the package name and version soprisma skills synccan copy it into agent harness directories and detect staleness from the installed packages rather than fetching from GitHub. The two upgrade skills fold into the prisma-8 router as its "upgrading" branch. (#30096)
7.10.0
Prisma ORM 7.10.0
Prisma ORM 7.10.0 introduces a compatibility package for running Prisma 7 alongside newer Prisma versions, secures Prisma Studio's local server, and includes fixes across Prisma Client and the PostgreSQL, MariaDB, Neon, SQLite, and Prisma Postgres Serverless adapters.
Highlights
Run Prisma 7 alongside Prisma 8
This release introduces @prisma/prisma7, a compatibility package that lets you retain a matching Prisma 7 CLI and configuration while installing Prisma 8 in the same project.
Once 7.10.0 is released, a side-by-side installation can use:
npm install --save-dev prisma@8 @prisma/prisma7@7.10.0
npm install @prisma/client@7.10.0Use prisma for the directly installed Prisma 8 CLI and prisma7 for Prisma 7:
npx prisma --version
npx prisma7 --version
npx prisma7 generate
npx prisma7 migrate dev
npx prisma7 db pushPrisma 7 now prefers version-specific configuration files, allowing its configuration to coexist with Prisma 8's prisma.config.* files:
// prisma7.config.ts
import { defineConfig } from '@prisma/prisma7/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: {
path: 'prisma/migrations',
},
})Without an explicit --config option, Prisma 7 searches for:
- Root-level
prisma7.config.*files. .config/prisma7.*files.- Existing
prisma.config.*files as a backwards-compatible fallback.
The supported extensions are .js, .ts, .mjs, .cjs, .mts, and .cts. An explicit config path always takes precedence:
npx prisma7 generate --config ./custom/prisma7.config.tsNew projects initialized by the Prisma 7 CLI use prisma7.config.ts. Existing projects containing only prisma.config.* continue to work without migration or additional warnings. If a prisma7.config.* file exists but cannot be loaded, Prisma reports the error rather than silently falling back to another configuration.
The prisma7 identity is carried through CLI help, version output, shell completion, initialization, migration, database, and generation guidance. Stable Prisma concepts such as schema.prisma, Prisma Migrate, @prisma/client, and PRISMA_* environment variables remain unchanged.
Together, the separate executable and configuration namespace make it possible to operate Prisma 7 and Prisma 8 side by side without command or config-file collisions.
#29949, #29969, #29994, #30000, #30002, #30020
Prisma Studio security hardening
Prisma Studio's local HTTP server now:
- Binds explicitly to
127.0.0.1instead of all network interfaces. - Rejects browser requests from origins other than the active
localhostor127.0.0.1Studio URL. - No longer returns wildcard CORS headers.
- Applies the same protections across Node.js, Bun, and Deno.
This prevents network clients or malicious websites from accessing Studio's database endpoints while Studio is running.
Prisma Client
- Fixed
P2002errors from nested writes someta.modelNameidentifies the model where the unique constraint violation occurred, including models using@@mapand@@schema. #29628 - Fixed automatically batched
findUniqueOrThrow()calls so every missing record rejects withP2025; later misses no longer resolve toundefined. #29654 - Parameter-chunked statements are now executed atomically in a transaction and rolled back if a later chunk fails. #29771
- Improved interactive transaction cleanup during
$disconnect(), including transactions whose driver-level startup is still in progress. #28768 - Prevented transaction cleanup failures after a timeout or backend termination from becoming unhandled promise rejections. #29611
- Fixed fluent relation queries when relation fields are literally named
selectorinclude. #29683 - Fixed handling of
DateandUint8Arrayvalues created in other JavaScript realms, such as iframes, jsdom, and Node.jsvmcontexts. #29177 - Invalid
Datevalues passed to$queryRawor$executeRawnow throwPrismaClientValidationErrorinstead of a generic error. #29718 - Fixed
moduleFormatinference for theprisma-clientgenerator in TypeScript projects usingmodule: "node16"or"nodenext". Generated output now follows the nearestpackage.jsontype, defaulting to CommonJS when absent. #29712 - Deserialized
Bytesvalues now own standaloneArrayBuffers rather than exposing unrelated contents from Node.js's sharedBufferpool. This applies to both regular and raw query results. #29701 - Fixed an incorrect logging context in the remote executor, including Accelerate-backed query execution. #28892
Client extensions and observability
-
Result-extension
computecallbacks now receive the current model name as a typed second argument:compute(data, modelName) { // ... }
The model name is also preserved when multiple extensions compose the same computed field. #29782
-
Improved OpenTelemetry context for remotely executed queries:
$on('query')callbacks run within the matchingdb_queryspan.- Events from one operation share the same trace.
- Error events are recorded as span exceptions.
- Log events continue to be emitted when tracing is disabled or their reported span is unavailable.
Driver adapters
MariaDB
@prisma/adapter-mariadbnow accepts an existingmariadbpool. External pools remain caller-owned unlessdisposeExternalPool: trueis supplied. #27992- Fixed pooled connection leaks during commit, rollback, and failed transaction startup. Connections are now returned with
release()and transaction-specific listeners are removed before reuse. #29612 - Added support for bracketed IPv6 addresses in both
mysql://andmariadb://connection strings. #29026 - Prevented malformed connection strings from exposing embedded passwords in retained debug output and diagnostic reports. #27992
PostgreSQL, Neon, and Prisma Postgres Serverless
- PostgreSQL deadlocks using SQLSTATE
40P01are now reported asP2034transaction write conflicts. #29717 - PostgreSQL
RESTRICTviolations using SQLSTATE23001are now reported asP2003, preserving an available field or constraint name. #29554 @prisma/adapter-pgnow preserves database constraint names when reporting unique constraint violations throughP2002. #29587- Prisma Postgres Serverless now prefers the named constraint for
P2002, falling back to parsed field names when no constraint name is available. #29801 - Fixed Neon HTTP adapter serialization for typed parameters such as
BytesandDateTime. #29747
SQLite
@prisma/adapter-better-sqlite3now converts previously unhandled SQLite result codes into typed database errors instead of exposing raw driver errors.- The complete
SQLITE_BUSYfamily is now mapped to socket timeout errors, with numeric extended result codes preserved where available.
CLI and Migrate
-
prisma generatecan now offer to install Prisma's agent skills. The opt-in prompt:- Is shown at most once per machine.
- Is skipped in CI, containers, Git hooks, npm lifecycle scripts, and watch mode.
- Is skipped when
--no-hintsis used or Prisma skills are already installed. - Times out after 30 seconds.
- Never causes generation to fail if installation is unsuccessful.
-
A globally installed CLI now warns during
prisma generatewhen its version differs from the project's localprismaor@prisma/client, and recommends running the local CLI. The check is best-effort and does not fail generation. #29593 -
prisma versionandprisma version --jsonnow include the resolved Prisma CLI package path, making global-versus-local installation issues easier to diagnose. #29573 -
Empty or generator-only schema files now report
Schema must contain a datasource blockfromdb pull,db push, andmigrate dev, rather than reaching the schema engine and potentially producing inconsistent errors. #29657 -
CLI commands now tolerate corrupt, unreadable, or unwritable command-state files. Invalid state is reinitialized, writes are atomic, and persistence failures fall back to in-memory state. #29609
-
...
v8.0.0-rc.5
v8.0.0-rc.5
The ORM command family now ships the unified CLI's command paths directly, the Postgres runtime survives dropped idle connections, aggregation respects the chain it terminates, and the raw lane lets an outer query reuse an inner query's typed return columns.
The upgrade recipe for this hop: the user recipe.
Breaking changes
-
The ORM command family is keyed by the unified CLI's mount paths —
@prisma/orm-toolchain's command family now publishes the six moved commands under their unified spellings (contract format,db migrate,migration ref list|set|delete,orm init) instead of the retired standalone grammar (format,migrate,ref …,init), and every help example and error remediation names those paths (with the{bin}placeholder instead of a hardcoded binary name). Through the unifiedprismaCLI nothing moves — these were already the mounted paths — but a host that mounts the family by key, or a script driving the workspace binary with the old spellings, must respell the six commands. (#30102)Before:
prisma migrate --to production prisma ref set staging 4cb4256After:
prisma db migrate --to production prisma migration ref set staging 4cb4256
Features
- A row-spec'd raw query exposes
.returns, a record of typed column refs, so an outer raw query can reuse an inner query's declared column (for example a CTE's aggregate) instead of restating its codec id. (#30075)
Fixes
aggregate()now reduces over exactly the rows a chain'stake/skip/cursor/distinct/distinctOndescribes, instead of silently reducing over every matching row. (#30067)groupBy()now scopes pre-group pagination to the rows it groups instead of dropping it, andGroupedCollectiongainedtake/skip/orderByto page the groups themselves. (#30092)- The Postgres runtime attaches
'error'listeners to every pool and client it creates or receives, so a dropped idle connection (database restart, pooler timeout, network blip) no longer crashes the process as an uncaught exception. Pools your own code constructs and uses directly still need a listener — see the upgrade recipe. (#30081) - The PSL language server recognizes connection errors raised by any bundled copy of vscode-jsonrpc, instead of crashing when a duplicated copy raised them. (#30077)
- CLI error text interpolates the configured migrations directory instead of assuming the default path. (#30041)
orm init's failure messages no longer name retired flags or binaries (--no-skill,--force,prisma-cli init); they point at the flags that exist (--skip-skills,--confirm <directory name>) and the mountedprisma orm init. (#30083)
v8.0.0-rc.4
v8.0.0-rc.4
The transition period for the old ORM config is over, and two fixes land for the consolidated prisma CLI stack. Most projects created before rc.2 need the config migration below; projects scaffolded by rc.2+ init need nothing.
The upgrade recipe for this hop: the user recipe.
Breaking changes
-
The deprecated config fallbacks are gone — the CLI no longer reads
prisma-next.config.tsand no longer accepts the flat (un-nested) config shape; both now fail loudly instead of warning. The only config read isprisma.config.tsin the envelope shape, and the workspaceprisma-nextbinary is retired — the unified CLI runs the ORM commands at the top level. Rename the file, wrap your ORM options indefinePrismaConfig({ orm: ormConfig({ … }) }), and keepimport 'dotenv/config'if your config readsprocess.env. See the user recipe for the exact rewrite. (#30058)Before:
// prisma-next.config.ts import { defineConfig } from '@prisma/orm-postgres/config'; export default defineConfig({ contract: './contract.prisma', db: { connection: process.env['DATABASE_URL']! } });
After:
// prisma.config.ts import 'dotenv/config'; import { definePrismaConfig } from '@prisma/cli-engine'; import { defineConfig as ormConfig } from '@prisma/orm-postgres/config'; export default definePrismaConfig({ orm: ormConfig({ contract: './contract.prisma', db: { connection: process.env['DATABASE_URL']! } }), });
Fixes
contract emitno longer crashes after writing its artifacts when the project root is a relative path —validateContractDeps()resolves the root before handing it to Node'screateRequire(), which requires an absolute path. (#30064)initscaffoldsdefinePrismaConfig, the current name for the config marker in@prisma/cli-engine0.2.0, instead of the deprecateddefineConfigalias. (#30064)
v8.0.0-rc.3
v8.0.0-rc.3
A single-purpose release: @prisma/orm-toolchain moves its exact @prisma/cli-engine peer from 0.1.1 to 0.2.0, so the unified prisma CLI can ship a release in which every mounted product runs on the one engine version it installs. There are no ORM API changes in this release.
Breaking changes
- The exact
@prisma/cli-enginepeer moves to 0.2.0 — engine 0.2.0 adds the credential-refresh exports and structured delegated output thatprisma@8.0.0-rc.4was built against but the registry's engine 0.1.1 does not contain, which is whynpx prisma@nextcurrently fails on import. This release pairs with theprismaCLI release that depends on it (8.0.0-rc.5); upgrade both together. No code changes — an operational peer move only. (#30056)
v8.0.0-rc.2
v8.0.0-rc.2
This release retires the prisma-next binary in favour of the unified prisma CLI, returns the default aggregates to plain JavaScript numbers with lossless variants beside them, makes CHECK constraints a declared part of the contract, and splits runtime row queries from non-returning writes. Almost every application will need to re-emit its contract and rename its config file, so read the breaking changes before upgrading.
Two upgrade recipes carry the mechanical translations for this hop: the user recipe and the extension-author recipe.
Breaking changes
-
This repository no longer publishes a CLI; the unified
prismaCLI replaces it — nothing published ships aprisma-nextbin anymore.@prisma/orm-toolchainexposes theormcommand family at@prisma/orm-toolchain/cliand no binary, and the database facades forward no launcher. Install@prisma/cli(the prisma-cli distribution, published undernextfor the v8 line) and replaceprisma-next <command>in package scripts and CI with the unified CLI. The config file moves with it:prisma-next.config.tsis deprecated in favour ofprisma.config.ts, and the config value is now engine-shaped, with your existing ORM config nested under anormsection. Both the old filename and the flat shape still load, each printing a deprecation warning on stderr, so the rename and the rewrap can land separately. See the user recipe. (#30005)Before:
// prisma-next.config.ts import { defineConfig } from '@prisma/orm-postgres/config'; export default defineConfig({ contract: './contract.ts', output: './generated' });
After:
// prisma.config.ts import { defineConfig } from '@prisma/cli-engine'; import { defineConfig as ormConfig } from '@prisma/orm-postgres/config'; export default defineConfig({ orm: ormConfig({ contract: './contract.ts', output: './generated' }), });
-
The default aggregates are JavaScript numbers again, with lossless variants beside them —
count(),sum()over an integer column, andavg()over an integer column all returnnumber. In8.0.0-rc.1they returned abigint, abigintor decimal string depending on the column's width, and a decimal string respectively. The lossless results moved to three new operations:countBigInt()returns abigint,sumBigInt()returns abigint, andavgDecimal()returns an exact decimal string (PostgreSQL only — SQLite has no decimal type and contributes none). Acount()or integersum()whose value passes ±(2^53 − 1) now raisesRUNTIME.DECODE_FAILEDrather than returning a rounded number, so move those calls to theBigIntvariants where the magnitude is real. Unchanged:min/max,sum/avgover a float column,sumoverDecimal,sumoverUnboundedInt, and the ORM'shaving(...)operands. The SQL builder's comparison operands do move, becausefns.gt(a, b)types both sides from one codec. The same PR also makes the wide-integer codecs refuse the wrong JavaScript type: aBigIntorUnboundedIntcolumn rejects anumberand aBigIntNumbercolumn rejects abigint, withRUNTIME.ENCODE_FAILEDnaming the type that arrived, where previously a number was accepted and stringified — which let a fractional value reach an integer column unremarked. See the user recipe. (#29930)Before:
const { total } = await db.User.aggregate((a) => ({ total: a.count() })); total === 2n; // bigint const busy = await db.sql.public.user .groupBy('kind') .having((_f, fns) => fns.gt(fns.count(), 1n)); // bigint literal
After:
const { total } = await db.User.aggregate((a) => ({ total: a.count() })); total === 2; // number — countBigInt() returns the bigint const busy = await db.sql.public.user .groupBy('kind') .having((_f, fns) => fns.gt(fns.count(), 1)); // plain number literal
-
Which aggregate methods exist is now the contract's answer — the aggregate methods are no longer declared on the ORM and SQL-builder surfaces outright. Each surface is derived from the operation names in the emitted
contract.d.ts'sAggregateTypesblock, so a target or extension can contribute an operation and it appears under its own name with no client change. PostgreSQL now contributes eight operations and SQLite seven. Re-emit your contract with the CLI'scontract emit: against a contract with noAggregateTypesblock — one authored in code withdefineContract(...)and handed straight to the client, or emitted before8.0.0-rc.1— every aggregate surface resolves toAggregateOperationsUnavailable, an empty type, and each call becomes a compile error. What this release changes is compile-time only — the separate runtime guard introduced in8.0.0-rc.1still stands, rejecting an aggregate whose operation and input codec the composed target does not declare withORM.AGGREGATE_UNSUPPORTEDbefore the query runs. Separately,count(field)now rendersCOUNT(<column>)instead of accepting the argument and discarding it, so a call that got past the types — a@ts-expect-error, acount(x as never), or dynamic dispatch — now counts that field's non-null values rather than rows. See the user recipe and the extension-author recipe. (#29922) -
CHECK constraints are declared in the contract, and introspection now sees all of them — the CHECK shape in
contract.jsonchanged from{ name, column, valueSet }to{ name, prefix, expression }, whereexpressionis the raw SQL predicate andnameis a content-addressed wire name (<prefix>_<8hex>, the convention indexes and RLS policies already use). An old-shape contract is rejected on read, so re-emitting is not optional. Three consequences to plan for. Your first migration plan after upgrading drops each old unsuffixed enum constraint and adds the wire-named one, which needsdestructiveto converge. Every list (many) column gains a declared element-non-null CHECK the planner previously created without declaring. And introspection stopped parsing predicates, so hand-written constraints earlier versions could not see are now visible — and an undeclared check is an extra thatdb verify --strictreports and a destructive-capable plan drops, so read the first plan fordropCheckConstraintoperations naming constraints you wrote yourself, and declare each one you want to keep with@@check(expression: "…", map: "<physical name>"). Two API changes ride along:addCheckConstraintin committed migration files takes anexpressioninstead of acolumn/valuespair, and thetypescriptContractoptions bag now requirescreateNamespacewhenever it passesdefaultControlPolicy. AnenumType()whose codec is numeric now throwsCONTRACT.ENUM_INVALIDwhile the contract is being built rather than failing later at migrate time. See the user recipe and the extension-author recipe. (#29892)Before:
this.addCheckConstraint({ schema, table, constraint, column: 'kind', values: ['admin', 'user'] });
After:
this.addCheckConstraint({ schema, table, constraint, expression: `"kind" IN ('admin', 'user')` });
-
Runtime row queries and non-returning writes are separate calls —
query()streams rows andexecute()resolves{ affectedRows }, which is how a write now reports its affected count without a precedingSELECT. Classify each call site by the result it consumes rather than replacing everyexecute: a select, a returning write, or any plan whose rows are iterated, indexed, or decoded moves toquery, while an insert, update, or delete that returns nothing stays onexecuteand readsaffectedRows. Prepared row consumption moves fromtarget.queryPrepared(prepared, params)toprepared.query(target, params). Runtime middleware splits the same way, intobeforeQuery/interceptQuery/afterQueryandbeforeExecute/interceptExecute/afterExecutewith a sharedbeforeCompile; query interception returns{ rows }and execute interception returns{ stats }. There is no operation discriminator, compatibility alias, or generic fallback hook. On Mongo,db.querystays the static builder and the row-executingdb.executefacade method is gone — build withdb.query, then execute through(await db.runtime()).query(plan). See the user recipe. (#29921) -
rawis a reserved storage namespace — the SQL surface exposes the whole-query raw statement tag asdb.sql.raw, so a storage namespace of that name would be unreachable through the builder while the emitted types still promised its tables. Building the client now raisesORM.NAMESPACE_RESERVEDnaming the namespac...
v8.0.0-rc.1
v8.0.0-rc.1
This is the first release on the v8 release-candidate line: releases are now versioned 8.0.0-rc.N instead of 0.x minors. It also makes every aggregate read back through the codec its target declares — count() returns a bigint — splits the SQL driver interface into a row-streaming call and a statistics call, and fixes four defects in query planning, emit, and driver error reporting.
The v8 release-candidate line
Releases are now versioned 8.0.0-rc.1, 8.0.0-rc.2, and so on, with the counter advancing on every release. "The v8 RC" is the product name; the number underneath iterates freely, so there is no promise that the last RC before 8.0.0 final is numbered rc.1. There are no further 0.x minors. The policy is written up in docs/oss/versioning.md. (#29899)
For every package this repository publishes, latest keeps tracking the newest release, RC included. These package names have no pre-v8 stable audience to protect — a bare npm install of one of them was already an early-access install, and still is. The bare prisma package is not published from this repository; its v8 CLI shim lives in prisma/prisma-cli.
Existing installs are not moved onto the RC line by npm update. Lockfiles pin resolved versions, and a ^0.x range can never match a 8.0.0-rc.N pre-release, because pre-releases do not satisfy stable ranges. Only a fresh install, or an explicit version change on your side, lands on the RC.
Development builds move to the same line: every push to main that does not change the root version publishes 8.0.0-rc.X-dev.N under the dev dist-tag.
An RC respin may still contain breaking changes. Until 8.0.0 final ships, the pre-1.0 latitude documented in docs/oss/versioning.md carries over: a new rc.N may remove or rename APIs, change the semantics of existing ones, or change the contract format. Read the breaking-changes section of each release before you upgrade.
Breaking changes
-
Aggregate results carry the codec their target declares — an aggregate is now read back through the codec its target declares for that result rather than through whatever the driver handed over, so aggregate application types change.
count()is abiginton both PostgreSQL and SQLite, at the top level and inside an include, and an empty relation reads0n. On PostgreSQL,sumoverint2/int4widens to abigint, whilesum(int8)andavgover any integer arenumericand read as exact decimal strings;min/maxkeep the column's own type, except overvarchar, which returnstext. On SQLite,sumover an integer column is abigintandavgis always anumber. Sweep your code for equality and arithmetic against an aggregate result (count === 2is false whencountis2n) and forJSON.stringifyover one (it throws on a bigint).having(...)operands are the exception and stay plain numbers — they are compared inside SQL and never cross a codec. Regenerate your contracts (prisma-next contract emit):contract.d.tsgains anAggregateTypesblock that both the ORM and the SQL builder resolve result types from, and against an older contract an aggregate resolves toneverin the ORM andunknownin the SQL builder. The type is not the only guard: an aggregate whose operation and input codec the composed target does not declare is rejected before the query runs, with the error codeORM.AGGREGATE_UNSUPPORTED. See the upgrade recipe and the extension-author recipe. (#29867)Before:
const rows = await posts.include('comments', (comments) => comments.count()).all(); rows[0].comments === 2; // number; 0 when the relation is empty
After:
const rows = await posts.include('comments', (comments) => comments.count()).all(); rows[0].comments === 2n; // bigint; 0n when the relation is empty
-
The SQL driver interface splits row streaming from statement statistics —
SqlQueryable(exported from@internal/sql-relational-core/ast) is now two methods wide:query()streams rows andexecute()returns{ affectedRows }. The separate prepared-execution method is gone; a prepared plan is expressed by an optionalpreparedStatementHandleon the request instead, and a driver branches on whether that property isundefined. Application code, query results, and the contract format are unaffected — this only matters if you implement or wrapSqlQueryableyourself, in which case update your implementation to the two-method shape. There is no upgrade recipe entry for this; the change is the interface itself. (#29907)Before:
interface SqlQueryable { execute<Row>(request: SqlExecuteRequest): AsyncIterable<Row>; executePrepared<Row>(request: PreparedExecuteRequest): AsyncIterable<Row>; query<Row>(sql: string, params?: readonly unknown[]): Promise<SqlQueryResult<Row>>; }
After:
interface SqlQueryable { query<Row>(request: SqlExecuteRequest): AsyncIterable<Row>; execute(request: SqlExecuteRequest): Promise<SqlStatementStats>; }
Features
prisma-next initinstalls oneprisma-8skill instead of eleven per-workflow skills, and removes the retired skill directories from every agent's install root on each run. Each skill is now installed by name —prisma-8,prisma-next-upgrade, andprisma-8-extension-upgrade— rather than by matching a wildcard against a directory, so a new skill landing beside them is not picked up by accident. (#29853)
Fixes
- A column, table, or model mapped to a name that is not a bare TypeScript identifier —
@map("has space"),@@map("data rows")— now emits a quoted property key incontract.d.tsinstead of producing a syntactically invalid file that killedcontract emit. String literals in emitted TypeScript also survive control characters and line separators, which previously produced the same failure by a different route. (#29889, #29898) - Nested
some/every/nonepredicates over a self-referential relation now keep a distinct SQL alias at every level, so an inner scope no longer shadows the parent it is supposed to correlate against. This covers one-to-one, many-to-one, one-to-many, implicit many-to-many, and explicit-junction many-to-many relations in both directions, and relations whose physical tables share a bare name across namespaces. (#29900) - Scalar reducers on a many-to-many include —
count(),sum(),avg(),min(),max()— now traverse the junction table instead of emitting a predicate against a foreign-key column that only exists on the junction, so a filtered relation count over a many-to-many relation returns the right number. (#29888) - A failed retry of a stale PostgreSQL prepared statement now surfaces a structured error envelope with the code
DRIVER.PREPARE_FAILED, carrying the normalized driver error as its cause, instead of an unlabelled failure. (#29907)
v0.17.0
v0.17.0
This is the namespace release: Prisma Next now publishes as 17 packages under the @prisma scope, and an application depends on exactly one database facade. It also completes the structured error-code scheme across every plane, makes relation-loading lossless for big numbers and temporal values, and gives every SQL index and RLS policy an exact, migratable name.
Breaking changes
-
One
@prismapackage per application — the@prisma-next/*scope is retired; nothing publishes under it again. An application depends on exactly one database facade —@prisma/orm-postgres,@prisma/orm-sqlite, or@prisma/orm-mongo— plus any extension packs it uses (now named@prisma/orm-extension-*); everything else arrives as the facade's exact-pinned dependencies. Regenerating your contract rewrites generated imports to facade entrypoints with nocontractHashchange. See the 0.16-to-0.17 upgrade recipe and the extension-author recipe. (#29864, #29880, #29883, #29884)Before:
"dependencies": { "@prisma-next/postgres": "0.16.0", "@prisma-next/framework-components": "0.16.0", "@prisma-next/sql-runtime": "0.16.0" }
After:
"dependencies": { "@prisma/orm-postgres": "0.17.0" }
-
Every published error is a structured envelope with a dotted code — the four legacy error systems (
PN-CLI-4001-style codes,RUNTIME.DECODE_FAILED-style codes, and codeless error classes) consolidate into one scheme: a structural envelope carrying aNAMESPACE.SUBCODEcode, recognized by theisStructuredErrortype predicate instead ofinstanceof. The ORM, contract-authoring, adapter/target, extension, and framework planes are all swept; legacy error classes (PslFormatError, the Supabase and SQL-escape classes, framework classes) are deleted. Prisma 7'sP1001-style codes are not carried over. (#1016, #1021, #1025, #1049, #1053, #1063)Before:
if (error instanceof PslFormatError) { report(error.diagnostics); }
After:
if (isStructuredError(error) && error.code === 'PSL.PARSE_FAILED') { report(error.meta.diagnostics); }
-
Content hashes are bare hex — the
sha256:prefix is gone from every surface (emitted contracts, migration manifests, refs, CLI output, and the database marker), and loaders reject the prefixed form. Contract hash values are unchanged;migrationHashvalues change. A codemod in the 0.16-to-0.17 recipe converts checked-in migration trees. (#1033) -
Migration contract snapshots move into a content-addressed store — per-migration sibling snapshot files and ref-paired copies are replaced by a single
migrations/snapshots/<hex>/store per migrations root; every distinct contract is stored once, andmigration.tsimports its bookend contracts from the store. This is a clean break with no fallback reader; a one-shot migrator (scripts/migrate-migrations-layout.mjs) converts existing trees and re-verifies everymigrationHashunchanged. (#1018, #1024) -
PostgreSQL native types are authored in type position; the
@db.*attribute channel is removed — write the native type directly (VarChar(255),Uuid,Timestamptz) instead of a base type plus@db.*attribute; remaining@db.X(args)usage fails with the exact replacement spelled out.Jsonre-binds to nativejsonstorage, with a newJsonbscalar for jsonb (what every pre-0.16Jsonfield meant — switch those fields to keep a byte-identical contract), andDatere-binds to the correctpg/date@1codec. (#1022, #1036, #1054)Before:
model User { id String @id @db.Uuid name String @db.VarChar(255) }
After:
model User { id Uuid @id name VarChar(255) }
-
Relation-loading and aggregates are lossless — values read through
.include()no longer pass through lossy JSON: every codec gains an explicit lossless JSON form produced inside the database. 64-bit integers arrive asbigintinstead of silently rounding, decimals as exact strings, and temporal columns decode correctly. Aggregate result types change accordingly:count()is abigint, decimal sums are strings. Regenerate your contract after upgrading. (#29844, #1023, #1051) -
SQL indexes and RLS policies are name-identified — every index and RLS policy carries an exact name in the contract, names travel on the wire, live objects can be adopted by exact name (
@@map), and a rename converges by renaming instead of drop-and-recreate. (#1047, #29807, #29865) -
extensionPacksconfig key renamed toextensions— inprisma-next.config.ts, the TS builder, client options, and the emitted contract's top-level key. The old key fails loudly. Because the key sits in the hashed contract bytes, all contract hashes change: re-emit and re-anchor migrations per the recipe. Two smaller key renames ride along:contract.source.sourceFormat→format, and the facadedefineConfigoptionoutputPath→output. (#1032) -
Count-only mutation terminals renamed —
createCount(...)/updateCount(...)/deleteCount()becomecreateAndCount(...)/updateAndCount(...)/deleteAndCount(); behavior andPromise<number>results are unchanged, with no compatibility aliases. (#1044)
Features
- Expression, partial, and unique indexes are authorable in both PSL and the TypeScript builder. (#1048)
contract inferreaches full fidelity — indexes, policy blocks, and@@rlsare captured — and signs the database, so introspect-then-verify works end to end on an adopted database. It also infers 1:1 relations from unique indexes. (#29808, #1038)- Every error code is documented on an in-repo reference page (221 codes), kept complete by a CI check, and error envelopes carry a
docsUrlpointing at their per-code anchor. (#1027, #29806)
Fixes
- MongoDB write results decode through their type codecs instead of returning raw wire values. (#29879)
- The Postgres runtime driver serializes queries per pinned client, fixing interleaved-query failures on a shared connection. (#29839)
- Mixed-case native-enum casts are quoted, so PascalCase enum type names survive Postgres case-folding. (#1034)
- Driver cursor streaming runs inside an explicit transaction, fixing dropped-portal failures under load. (#1017)
- Published type declarations name only dependencies a consumer will actually have installed. (#29862)