This release includes 8 breaking changes for platform teams planning a safe upgrade.
✓ No known CVEs patched in this version
Topics
Affected surfaces
Summary
AI summaryBroad release touches Breaking changes, New contributors, string, and https://github.com/prisma/prisma-next/pull/921.
Full changelog
v0.15.0
This release ships Postgres row-level security end-to-end (policies for every operation, explicit @@rls enablement, role declarations — authored in PSL or TypeScript, planned by migration plan, drift caught by db verify), native Postgres enums (external adoption and a managed lifecycle), the complete introspected Supabase contract, a PSL language server (prisma-next lsp) with formatting, completions, and semantic highlighting, native scalar-list columns, PSL many-to-many authoring, and one unified schema differ behind db verify and migration planning. SQL ORM includes now decode through codecs, matching top-level reads.
Breaking changes
-
SQL ORM includes decode through codecs — every scalar field of an included relation now decodes through its contract-bound codec, matching top-level query results. Code that relied on included fields keeping the database's raw JSON representation must be updated: Postgres
byteainclude fields returnUint8Arrayinstead of\x-prefixed hex text, timestamp fields returnDateinstead of strings, and custom codec-backed fields return whatever the codec'sdecodeJsonproduces. Custom SQL codec authors:encodeJson/decodeJsonnow use the exact scalar shape the database produces inside JSON values — see the extension-author recipe for the built-in representation changes. (#942)Before:
const [post] = await db.orm.public.Post.find({ include: { author: true } }); post.author.avatar; // '\\x89504e…' (raw hex text) post.author.createdAt; // '2026-07-01T12:00:00' (string)After:
post.author.avatar; // Uint8Array post.author.createdAt; // Date -
db verify --jsonreports a singleschema.issueslist — the splitschema.issues/schema.schemaDiffIssuespair collapses into oneschema.issuesarray of{ path, reason, message, expected?, actual? }, and the retiredoutcomefield is replaced byreason('missing'→'not-found','extra'→'not-expected','mismatch'→'not-equal'). The same collapse applies toschema.warnings. Update scripts or CI steps that readschemaDiffIssuesor compare.outcome. See the 0.14→0.15 upgrade recipe. (#921)Before:
{ "schema": { "issues": [], "schemaDiffIssues": [{ "outcome": "missing", "message": "…" }] } }After:
{ "schema": { "issues": [{ "reason": "not-found", "path": ["…"], "message": "…" }] } } -
RLS policies require
@@rlson the target model — RLS enablement is an explicit, authored table attribute. Apolicy_*block'stargetmodel must declare@@rls, orcontract emitfails withPSL_EXTENSION_TARGET_MODEL_MISSING_ATTRIBUTE. Plan semantics follow the marker: a marked table with RLS off plansENABLE ROW LEVEL SECURITY, removing every policy keeps RLS enabled (fail-closed deny-all), and removing@@rlsplansDISABLE ROW LEVEL SECURITY(requires the destructive allowance). Renaming only a policy's name plans a singleALTER POLICY … RENAME TOinstead of drop+create. Extension authors constructingPostgresTableSchemaNodeby hand must supply the now-requiredrlsEnabledboolean. (#945)Before:
model Profile { id Uuid @id userId Uuid @unique }After:
model Profile { id Uuid @id userId Uuid @unique @@rls } -
Extension authors: SQL contract authoring requires a target
createNamespace— the SQL family no longer materialises a placeholder namespace, soprismaContract(...)/defineContract(...)from@prisma-next/sql-contract-psl/@prisma-next/sql-contract-tsneed the target's namespace factory (postgresCreateNamespace/sqliteCreateNamespace); target-packdefineContractwrappers already supply it, so app authors are unaffected.SqlNamespaceis now an abstract class;buildSqlNamespace,buildSqlNamespaceMap,SqlBoundNamespace, andSqlUnboundNamespaceare removed, and hand-written namespace literals carry the targetkind(e.g.'postgres-schema') instead of'sql-namespace'. See the extension-author recipe. (#864) -
Extension authors: the coordinate-based schema-diff SPI is retired — the migration planner and
db verifynow run on one generic node differ.collectSqlSchemaIssues/collectSqlSchemaIssuesPerNamespace,diffPostgresDatabaseSchema, andSqlControlTargetDescriptor.diffDatabaseSchemaare removed (usediffSchemasor a target'sbuildXPlanDiff);MigrationPlanner.plan()'skeepDiffIssuepredicate is replaced by anownershiporacle; the issue typesBaseSchemaIssue/SchemaIssue/EnumValuesChangedIssueare gone —SchemaDiffIssueis the single issue shape everywhere, including the codecverifyTypehook; andgraphWalkStrategyis renamedresolveRecordedPathin@prisma-next/migration-tools/aggregate. See the extension-author recipe. (#921, #894) -
Extension authors: restricted-column typing goes through the codec — a column restricted to a value set derives its TS literal union by rendering each stored value through the codec's
renderValueLiteral(value, side), replacing the framework's deleted domain-enum override. Custom codec descriptors used by enum/restricted columns must implement it, or the column widens to the codec's output type. (#896) -
Extension authors: Mongo
deriveJsonSchemasources enums from value sets — the fourth argument ofderiveJsonSchema/derivePolymorphicJsonSchemachanges from a domain-enum map to a value-set map (contract.storage.namespaces[<ns>].entries.valueSet). Callers throughmongoContract(...)/defineContract(...)need no change. (#900) -
Extension authors:
ScalarFieldState's first generic is the column descriptor —ScalarFieldState<'pg/text@1', …>becomesScalarFieldState<ColumnTypeDescriptor<'pg/text@1'>, …>, so field states preserve the whole descriptor type (including native-enum member tuples). Built contract types also keep literalnativeType/typeParamsinstead of widening tostring. (#958) -
Extension authors:
native_enumentities serialize intocontract.json, keyed by physical type name — packs declaring native Postgres enums must re-emit their bundled contract so theentries.native_enummaps land in the published artifacts (this is what lets a consumer'scontract infersubtract pack-owned enum types). Code addressing an entry by key switches from the PascalCase name to the physical Postgres type name (entries.native_enum.aal_level, not.AalLevel). (#946, #954)
Features
-
Postgres row-level security, end-to-end — PSL gains
policy_select,policy_insert,policy_update,policy_delete, andpolicy_allblocks (withusing/withCheckpredicates and per-role targeting), the@@rlsenablement attribute, and standaloneroledeclarations insidenamespace unbound { }.migration planplans the full lifecycle (ENABLE/DISABLE ROW LEVEL SECURITY, policy create/drop, rename viaALTER POLICY), anddb verifyfails on policy drift and on declared roles the live cluster lacks. The same surface is authorable in the TypeScript DSL (policySelect(...),rlsEnabled(model),role(name)), producing wire-name-identical contracts. (#771, #868, #945, #950, #957, #959) -
Native Postgres enums —
CREATE TYPE … AS ENUMtypes are first-class again, this time as explicit entities. External types the database already owns (e.g. Supabase'sauth.aal_level) are declared vianative_enumblocks, typed as member-value literal unions, adopted bycontract infer, and read at runtime through the new Postgres-onlydb.nativeEnumsaccessor. Managed native enums get a migration lifecycle: create/delete, and member addition viaALTER TYPE … ADD VALUE(other member changes are refused with a converting-migration hint). Also authorable in the TypeScript DSL vianativeEnum(name, ...values)+field.column(pg.enum(handle)), with the member union visible intypeof contractwithout an emit. (#906, #944, #949, #970, #935, #958) -
The complete Supabase contract —
@prisma-next/extension-supabasenow ships the full introspected description of everything Supabase owns: everyauthandstoragetable, all native enum types, and the three platform roles (anon,authenticated,service_role), up from the previous 5-table minimum. A secondarydb.asServiceRole().supabase.{sql,orm}admin root reads Supabase-internal tables asservice_role, and the extension ships with docs, a real-Supabase acceptance harness, and a user-facingprisma-next-supabaseskill. (#845, #960, #985, #987) -
PSL language server — a new
prisma-next lspsubcommand serves diagnostics, formatting, completions (types and block templates), semantic highlighting, folding regions, and symbol-table diagnostics over LSP, backed by the fault-tolerant CST parser (which now fully replaces the legacy parser).prisma formatformats PSL from the CLI, and a browser playground wires a Monaco editor to the language server. (#852, #851, #850, #857, #862, #871, #878, #869, #856, #887, #972) -
PSL native scalar lists — scalar-list fields (
String[],Int[], …) lower to native array storage columns instead of a JSONB fallback, end-to-end: author, migrate, and infer, gated on the adapter-reportedscalarListcapability. (#870, #846) -
PSL authors many-to-many — an
N:Mrelation with athroughjunction is now authorable in PSL, completing the M:N surface whose read side landed in 0.14. (#819) -
Per-migration contract snapshots — each applied migration persists its contract snapshot in a 1:1 ledger companion table, and the
Migrationbase class takes typed start/end contract JSON, exposingthis.startContract/this.endContractviews for data-transform migrations. (#908, #879) -
Client-safe static surface — new
@prisma-next/{postgres,sqlite,mongo}/staticentrypoints export<target>Static({ contractJson }), a driver-freeExecutionContextplus derivedenums, query builder,raw, andcontract— safe to import in client bundles. The runtime facades also exposedb.contextanddb.contract. (#888) -
Mongo enums, end-to-end — enums are authorable for MongoDB in PSL and the TypeScript builder, enforced at the database layer via a planner-generated
$jsonSchemavalidator, and typed from a stored value set the same way SQL enums are. The Mongo client also gainsdb.rawanddb.execute(plan). (#834, #900, #880) -
Extension-aware
contract infer—contract inferomits database elements a stack extension pack's contract already describes, and resolves a foreign key into pack-owned space as a qualified cross-space relation (e.g.supabase:auth.AuthUser) instead of re-declaring the pack's tables. (#919) -
Variant-declared relations in the ORM — the
.variant('X')-narrowed accessor surfaces relations the variant model declares (filterable and includable), alongside the base model's relations. (#933, #976) -
Enum
@@typeinference — a PSLenumblock may omit@@type; the codec is inferred from the member values (text for string members, int for integers). (#905) -
@relation(index: false)andinetcolumns — PSL's@relationgains an optionalindexargument for foreign keys whose columns genuinely have no backing index (contract inferemits it automatically), and the Postgres target gains apg/inet@1codec soinetcolumns are authorable asString @db.Inetand inferrable. (#960)
Fixes
-
@default(false)survives emission — the contract canonicalizer no longer stripsvalue: falsefrom resolved defaults, so a boolean-falsecolumn default is present in the emittedcontract.jsonand round-trips against live introspection. Re-emitting an affected contract changes its storage hash. (#904) -
Mongo reshaping reads decode through codecs — aggregation reads through
$project/$addFieldsstages decode their output fields instead of returning raw BSON (a projected_idnow comes back decoded, not as a rawObjectId). (#897) -
pgbindings resolve by structure — a caller-supplied Pool/Client from a duplicatedpgcopy in a bundle now resolves correctly instead of throwingUnable to determine pg binding typeat boot; newisPgPool/isPgClientguards are exported from@prisma-next/postgres/runtime. (#969) -
Array columns verify cleanly — a scalar-list column's derived schema IR keeps the bare element type with
many: true(previously every list column verifiednot-equalagainst live introspection); Postgres introspection also excludes expression-keyed indexes and no longer collides unique and non-unique indexes over identical columns. (#960) -
Stack-missing migration errors name the failing operation — the error raised when a migration references an operation the stack doesn't provide now says which operation. (#953)
New contributors
Breaking Changes
- SQL ORM decode through codecs changes scalar field types (e.g., bytea → Uint8Array, timestamp → Date).
- `db verify --json` now reports a single `schema.issues` list with updated reason fields.
- RLS policies require explicit `@@rls` attribute on target models; removal or addition of the attribute changes RLS enable/disable planning.
- Extension authors must provide a target `createNamespace` for SQL contract authoring; removed namespace helpers and abstract class change.
- Retired coordinate‑based schema‑diff SPI; use generic node differ APIs instead.
- Restricted-column typing now goes through the codec; custom codecs must implement `renderValueLiteral`.
- Mongo `deriveJsonSchema` sources enums from value sets rather than domain‑enum maps.
- `ScalarFieldState` first generic is now the column descriptor, preserving full type information.
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About Prisma Next
All releases →Related context
Earlier breaking changes
- v0.13.0 Codec‑resolution SPI now requires leading `namespaceId` argument.
- v0.13.0 Contract storage IR now keyed by namespace envelope; re‑emit contract to update shape.
- v0.13.0 MTI variant tables now emit a base‑PK link column with cascading foreign key.
- v0.13.0 Telemetry defaults to opt-out; set PRISMA_NEXT_DISABLE_TELEMETRY=1 or DO_NOT_TRACK=1 to disable.
- v0.12.0 Models and value objects moved to namespaced domain plane (`contract.domain.namespaces.<ns>`).
Beta — feedback welcome: [email protected]