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/app/upgrades/0.15-to-0.16/instructions.md

upgrading/app/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). 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. There is no working code to migrate: delete the import and whatever test setup called bootstrapSupabaseShim. 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. If you run db verify --strict against a table with an identity column whose contract does not declare @default(autoincrement()) (because it predates this fix), verify now reports that default as an unexpected extra. Re-run contract infer for the affected table, or add @default(autoincrement()) by hand, to match what the database has always generated.
  • 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. If you do re-run contract infer against a database 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 application code accesses via .include()/.select()/the generated TypeScript types, so update those call sites to the corrected name.
  • id: scalar-type-descriptors-channel-removed summary: | The scalar-type descriptor channel is retired in favour of the unified authoring type namespace. Projects with custom control-stack setups that import createPostgresScalarTypeDescriptors / createSqliteScalarTypeDescriptors, or that read scalarTypeDescriptors from a control stack or contract-source context, must migrate: those exports are deleted, and scalar types are now zero-arg type-constructor contributions in the component's authoring.type namespace — e.g. String: { kind: 'typeConstructor', output: { codecId: 'pg/text@1', nativeType: 'text' } }. Read the scalar type names via stack.scalarTypes, or the full name -> { codecId, nativeType } map via collectScalarTypeConstructors(stack.authoringContributions.type) from @internal/framework-components/authoring. Standard target setups (@internal/postgres, @internal/sqlite) supply the contributions themselves. detection: glob: "**/*.{ts,mts,cts}" contains: - "createPostgresScalarTypeDescriptors" - "createSqliteScalarTypeDescriptors" - "scalarTypeDescriptors" 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. Postgres schemas that use Json and mean jsonb storage (which every pre-0.16 Json field did) must switch those fields — and types {} aliases — to Jsonb, then re-run prisma-next contract emit; with Jsonb the emitted contract.json is byte-identical to the pre-0.16 output. A field left as Json now emits a native json column and a new storage hash, which against an existing jsonb database is a schema change. The legacy @db.Json attribute path is unchanged (Json @db.Json still yields pg/json@1 / json), and sqlite/mongo Json bindings are untouched. The TS builder surface (field.json(), jsonbColumn) is unchanged and stays jsonb. detection: glob: "**/*.prisma" contains: - "Json" anyMatch: true
  • id: default-generators-no-longer-set-storage summary: | @default(<generator>) no longer influences a column's storage — the type position is the only storage decider. Pre-0.16, a generator default on a bare String field re-picked the column's storage to a sized char: String @default(uuid()) / @default(uuid(7)) emitted sql/char@1 / character(36), @default(cuid(2)) character(24), @default(nanoid()) character(21) (or character(<size>) for nanoid(<size>)), and @default(ulid()) character(26). From 0.16 such fields emit the target's String storage (postgres: pg/text@1 / text) with the same execution-time generator, so a re-emit produces a new storage hash — against an existing database created with the char storage this is a schema change. To keep the prior storage byte-identical, name it in the type position: Char(36) @default(uuid()), Char(24) @default(cuid(2)), Char(21) @default(nanoid()) (or Char(<size>) for a sized nanoid), Char(26) @default(ulid()) — or adopt native Uuid for uuid() if a uuid-typed column is preferred (that is a schema change too). Then re-run prisma-next contract emit and, if you accepted a storage change, plan/apply the matching migration. Generator applicability validation is unchanged (uuid() on Int still fails with PSL_INVALID_DEFAULT_APPLICABILITY), and the TS builder presets (field.id.uuidv4String(), field.generated(uuidv4()), …) are untouched — they bundle their char(N) storage explicitly. detection: glob: "**/*.prisma" contains: - "@default(uuid(" - "@default(cuid(" - "@default(nanoid(" - "@default(ulid(" anyMatch: true