prisma-8

Use when working in a project that depends on @prisma/orm-postgres, @prisma/orm-sqlite, or @prisma/orm-mongo (Prisma 8, formerly Prisma Next): editing contract.prisma or a contract.ts builder, running `prisma contract emit`, planning or applying migrations, editing migration.ts, writing db.orm / db.sql / db.query queries, wiring db.ts or middleware, integrating a build tool, using the Supabase extension or RLS, or reading a dotted error code such as MIGRATION.HASH_MISMATCH. Use when the user asks "what is Prisma 8", "where do I start", or compares it to another ORM. Use when the user asks to upgrade or bump Prisma 8 in an app or an extension package. Use when you see @internal/* or @prisma/orm-* imports, prisma.config.ts with definePrismaConfig, or contract.json / contract.d.ts. Do not use for Prisma ORM 7 or earlier (schema.prisma + @prisma/client).

Install
npx skills add 'https://github.com/prisma/orm/tree/main/skills/prisma-8'
Download bundle ↓
main · fac8604Scanned 2026-09-17

Contributors

GitHub-linked commit authors for this SKILL.md at the saved revision. Co-authors and history before file renames are not included.

File history ↗

upgrading/extension/upgrades/0.15-to-0.16/instructions.md

upgrading/extension/upgrades/0.15-to-0.16/instructions.mdBrowse 76 files
View on GitHub
← Back to SKILL.md

from: "0.15" to: "0.16" changes:

  • id: extension-supabase-test-utils-export-removed summary: | @internal/extension-supabase no longer exports the ./test/utils subpath (bootstrapSupabaseShim), and it is no longer a pattern to copy for extension test tooling. The import typechecked (types shipped in dist), but the subpath never worked from npm — the shim reads fixture .sql files that were never published, so every call failed with ENOENT before touching a database. Delete any import of @internal/extension-supabase/test/utils; keep hermetic test helpers package-internal (tests import them by source path) rather than publishing them as subpath exports whose on-disk fixtures don't ship. detection: glob: "**/*.{ts,mts,cts,js,mjs}" contains: - "extension-supabase/test/utils" anyMatch: true
  • id: identity-columns-need-explicit-default-under-strict-verify summary: | contract infer now emits @default(autoincrement()) for a Postgres GENERATED ALWAYS AS IDENTITY / GENERATED BY DEFAULT AS IDENTITY column (previously it emitted a bare column with no default, since Postgres reports no column_default for an identity column). Symmetrically, db verify introspecting a live identity column now resolves its default to autoincrement() too (previously it resolved to nothing). This only changes db verify --strict — without --strict, an undeclared live default is tolerated either way (and it is fully tolerated regardless of strictness under control: 'external', the posture most extension packs declare). If your pack's own tests run db verify --strict against a table with an identity column whose contract does not declare @default(autoincrement()), verify now reports that default as an unexpected extra. Re-run contract infer for the affected table, or add @default(autoincrement()) by hand.
  • id: pluralize-back-relation-names-no-longer-double-pluralize summary: | contract infer's back-relation field name generation used a hand-rolled pluralization rule that appended es to any table name already ending in s/x/z/ch/sh, doubling an already-plural table name (sessions -> sessionses). contract infer now uses real inflection (the pluralize library) and produces the correct name (sessions stays sessions; a genuinely singular status still becomes statuses). This only affects a future contract infer run — an already-generated .prisma file is untouched, so nothing breaks until you next re-run infer for your pack. If you do re-run contract infer against a schema with an already-plural table name, diff the regenerated .prisma file for any back-relation field whose name changed — that's a public field name your pack's consumers access via .include()/.select()/the generated TypeScript types, so a rename is a breaking change to your pack's own published surface, to be versioned and documented like any other.
  • id: scalar-type-descriptors-channel-removed summary: | ComponentMetadata.scalarTypeDescriptors is retired — the unified authoring type namespace is now the single channel for scalar types. If your extension/adapter descriptor declared scalarTypeDescriptors: new Map([['String', 'pg/text@1'], ...]), move each entry to a zero-arg type-constructor contribution in the descriptor's authoring.type namespace: String: { kind: 'typeConstructor', output: { codecId: 'pg/text@1', nativeType: 'text' } }. The nativeType is now explicit — it was previously derived from the codec's first target type, so check the codec manifest for the value to inline. Code that read ControlStack.scalarTypeDescriptors / ContractSourceContext.scalarTypeDescriptors should read stack.scalarTypes (the scalar type names) or derive the name -> { codecId, nativeType } map via collectScalarTypeConstructors(stack.authoringContributions.type) from @internal/framework-components/authoring. assembleScalarTypeDescriptors is deleted, and validateScalarTypeCodecIds now takes the authoring type namespace instead of a descriptor map. detection: glob: "**/*.{ts,mts,cts}" contains: - "scalarTypeDescriptors" - "assembleScalarTypeDescriptors" anyMatch: true
  • id: postgres-json-rebound-to-native-json summary: | On the postgres target the PSL Json scalar re-binds from pg/jsonb@1 / jsonb to pg/json@1 / json; a new bare Jsonb scalar carries pg/jsonb@1 / jsonb (postgresScalarAuthoringTypes in @internal/adapter-postgres). Extension test schemas and fixtures that author postgres Json fields and mean jsonb storage must switch those fields to Jsonb; assertions that pin the Json name's derived binding (e.g. over collectScalarTypeConstructors(stack.authoringContributions.type) or stack.scalarTypes) now expect Json -> { codecId: 'pg/json@1', nativeType: 'json' } plus the new Jsonb -> { codecId: 'pg/jsonb@1', nativeType: 'jsonb' } entry. PSL value-object storage columns still emit jsonb (the interpreter now prefers the target's Jsonb scalar and falls back to Json). The legacy @db.Json attribute path (NATIVE_TYPE_SPECS) is unchanged, as are sqlite/mongo Json bindings and the TS builder surface (field.json(), jsonbColumn). detection: glob: "**/*.{prisma,ts,mts,cts}" contains: - "Json" anyMatch: true
  • id: default-generators-no-longer-set-storage summary: | @default(<generator>) never mutates a column's storage any more — the type position is the only storage decider — and the whole generator-storage-override SPI is retired with it. Removed surfaces: MutationDefaultGeneratorDescriptor.resolveGeneratedColumnDescriptor (@internal/framework-components/control) — generator descriptors are now { id, applicableCodecIds?, buildPhases? } only, and applicableCodecIds remains the validation channel (PSL_INVALID_DEFAULT_APPLICABILITY on mismatch); the transitional baseScalar marker on AuthoringTypeConstructorDescriptor and ScalarTypeConstructorOutput (@internal/framework-components/authoring) — scalar type-constructor contributions and the derived scalar view are plain { codecId, nativeType, typeParams? } again; and the @internal/ids exports resolveBuiltinGeneratedColumnDescriptor / GeneratedColumnDescriptor (the TS spec helpers uuidv4(), nanoid(), … still return GeneratedColumnSpec bundling their explicit sql/char@1 column). Packs that registered a generator descriptor with a storage-resolution hook must drop the hook; PSL schemas in extension fixtures relying on String @default(uuid()/cuid()/nanoid()/ulid()) producing character(N) columns must either accept the target String storage (postgres: pg/text@1 / text) or author the char storage explicitly in the type position (Char(36) @default(uuid()), …), then re-emit. detection: glob: "**/*.{ts,mts,cts,prisma}" contains: - "resolveGeneratedColumnDescriptor" - "resolveBuiltinGeneratedColumnDescriptor" - "baseScalar" - "@default(uuid(" - "@default(cuid(" - "@default(nanoid(" - "@default(ulid(" anyMatch: true