Skip to content

Prisma Next

v0.15.0 Breaking

This release includes 8 breaking changes for platform teams planning a safe upgrade.

Published 11d CLI & Terminal
✓ No known CVEs patched
Read the diff → Tool health → What is this tool? →

✓ No known CVEs patched in this version

Topics

loggy-core loggy-terminal

Affected surfaces

breaking_upgrade auth rbac

Summary

AI summary

Broad 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 bytea include fields return Uint8Array instead of \x-prefixed hex text, timestamp fields return Date instead of strings, and custom codec-backed fields return whatever the codec's decodeJson produces. Custom SQL codec authors: encodeJson / decodeJson now 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 --json reports a single schema.issues list — the split schema.issues / schema.schemaDiffIssues pair collapses into one schema.issues array of { path, reason, message, expected?, actual? }, and the retired outcome field is replaced by reason ('missing''not-found', 'extra''not-expected', 'mismatch''not-equal'). The same collapse applies to schema.warnings. Update scripts or CI steps that read schemaDiffIssues or 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 @@rls on the target model — RLS enablement is an explicit, authored table attribute. A policy_* block's target model must declare @@rls, or contract emit fails with PSL_EXTENSION_TARGET_MODEL_MISSING_ATTRIBUTE. Plan semantics follow the marker: a marked table with RLS off plans ENABLE ROW LEVEL SECURITY, removing every policy keeps RLS enabled (fail-closed deny-all), and removing @@rls plans DISABLE ROW LEVEL SECURITY (requires the destructive allowance). Renaming only a policy's name plans a single ALTER POLICY … RENAME TO instead of drop+create. Extension authors constructing PostgresTableSchemaNode by hand must supply the now-required rlsEnabled boolean. (#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, so prismaContract(...) / defineContract(...) from @prisma-next/sql-contract-psl / @prisma-next/sql-contract-ts need the target's namespace factory (postgresCreateNamespace / sqliteCreateNamespace); target-pack defineContract wrappers already supply it, so app authors are unaffected. SqlNamespace is now an abstract class; buildSqlNamespace, buildSqlNamespaceMap, SqlBoundNamespace, and SqlUnboundNamespace are removed, and hand-written namespace literals carry the target kind (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 verify now run on one generic node differ. collectSqlSchemaIssues / collectSqlSchemaIssuesPerNamespace, diffPostgresDatabaseSchema, and SqlControlTargetDescriptor.diffDatabaseSchema are removed (use diffSchemas or a target's buildXPlanDiff); MigrationPlanner.plan()'s keepDiffIssue predicate is replaced by an ownership oracle; the issue types BaseSchemaIssue / SchemaIssue / EnumValuesChangedIssue are gone — SchemaDiffIssue is the single issue shape everywhere, including the codec verifyType hook; and graphWalkStrategy is renamed resolveRecordedPath in @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 deriveJsonSchema sources enums from value sets — the fourth argument of deriveJsonSchema / derivePolymorphicJsonSchema changes from a domain-enum map to a value-set map (contract.storage.namespaces[<ns>].entries.valueSet). Callers through mongoContract(...) / defineContract(...) need no change. (#900)

  • Extension authors: ScalarFieldState's first generic is the column descriptorScalarFieldState<'pg/text@1', …> becomes ScalarFieldState<ColumnTypeDescriptor<'pg/text@1'>, …>, so field states preserve the whole descriptor type (including native-enum member tuples). Built contract types also keep literal nativeType / typeParams instead of widening to string. (#958)

  • Extension authors: native_enum entities serialize into contract.json, keyed by physical type name — packs declaring native Postgres enums must re-emit their bundled contract so the entries.native_enum maps land in the published artifacts (this is what lets a consumer's contract infer subtract 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, and policy_all blocks (with using / withCheck predicates and per-role targeting), the @@rls enablement attribute, and standalone role declarations inside namespace unbound { }. migration plan plans the full lifecycle (ENABLE / DISABLE ROW LEVEL SECURITY, policy create/drop, rename via ALTER POLICY), and db verify fails 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 enumsCREATE TYPE … AS ENUM types are first-class again, this time as explicit entities. External types the database already owns (e.g. Supabase's auth.aal_level) are declared via native_enum blocks, typed as member-value literal unions, adopted by contract infer, and read at runtime through the new Postgres-only db.nativeEnums accessor. Managed native enums get a migration lifecycle: create/delete, and member addition via ALTER TYPE … ADD VALUE (other member changes are refused with a converting-migration hint). Also authorable in the TypeScript DSL via nativeEnum(name, ...values) + field.column(pg.enum(handle)), with the member union visible in typeof contract without an emit. (#906, #944, #949, #970, #935, #958)

  • The complete Supabase contract@prisma-next/extension-supabase now ships the full introspected description of everything Supabase owns: every auth and storage table, all native enum types, and the three platform roles (anon, authenticated, service_role), up from the previous 5-table minimum. A secondary db.asServiceRole().supabase.{sql,orm} admin root reads Supabase-internal tables as service_role, and the extension ships with docs, a real-Supabase acceptance harness, and a user-facing prisma-next-supabase skill. (#845, #960, #985, #987)

  • PSL language server — a new prisma-next lsp subcommand 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 format formats 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-reported scalarList capability. (#870, #846)

  • PSL authors many-to-many — an N:M relation with a through junction 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 Migration base class takes typed start/end contract JSON, exposing this.startContract / this.endContract views for data-transform migrations. (#908, #879)

  • Client-safe static surface — new @prisma-next/{postgres,sqlite,mongo}/static entrypoints export <target>Static({ contractJson }), a driver-free ExecutionContext plus derived enums, query builder, raw, and contract — safe to import in client bundles. The runtime facades also expose db.context and db.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 $jsonSchema validator, and typed from a stored value set the same way SQL enums are. The Mongo client also gains db.raw and db.execute(plan). (#834, #900, #880)

  • Extension-aware contract infercontract infer omits 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 @@type inference — a PSL enum block may omit @@type; the codec is inferred from the member values (text for string members, int for integers). (#905)

  • @relation(index: false) and inet columns — PSL's @relation gains an optional index argument for foreign keys whose columns genuinely have no backing index (contract infer emits it automatically), and the Postgres target gains a pg/inet@1 codec so inet columns are authorable as String @db.Inet and inferrable. (#960)

Fixes

  • @default(false) survives emission — the contract canonicalizer no longer strips value: false from resolved defaults, so a boolean-false column default is present in the emitted contract.json and 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 / $addFields stages decode their output fields instead of returning raw BSON (a projected _id now comes back decoded, not as a raw ObjectId). (#897)

  • pg bindings resolve by structure — a caller-supplied Pool/Client from a duplicated pg copy in a bundle now resolves correctly instead of throwing Unable to determine pg binding type at boot; new isPgPool / isPgClient guards 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 verified not-equal against 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

Track Prisma Next

Get notified when new releases ship.

Sign up free

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]