Skip to content

feat(compat): Prisma 7 driver adapter for PostgreSQL and MySQL#175

Merged
jeremydaly merged 3 commits into
mainfrom
feat/compat-prisma
Jun 16, 2026
Merged

feat(compat): Prisma 7 driver adapter for PostgreSQL and MySQL#175
jeremydaly merged 3 commits into
mainfrom
feat/compat-prisma

Conversation

@jeremydaly

Copy link
Copy Markdown
Owner

Summary

This adds a Prisma driver adapter so you can run Prisma Client against the Aurora Data API, on both Postgres and MySQL. You import createPrismaPgAdapter (or the MySQL one), hand it to new PrismaClient({ adapter }), and Prisma talks to the Data API instead of opening its own connection.

Prisma is the one ORM where our usual trick doesn't work. The pg, mysql2, and knex layers all pretend to be a Node driver and let the ORM call query(). Prisma won't take an injected driver that way. Its query engine normally opens its own socket, so this uses Prisma's driver-adapter API instead. That's the same path Neon and PlanetScale use for their serverless drivers.

The adapter stays thin. It holds a normal init() client and reuses everything that already works: query sending, the scale-to-zero retry, result formatting, and the transaction methods. The only new code is the part Prisma actually needs.

  • mapping the Data API's column metadata to Prisma's column types
  • turning Prisma's $1 / ? params into Data API params, and rewriting Postgres array params into ARRAY[...], since the Data API can't bind arrays directly
  • translating Data API errors into Prisma's error shape

Two small bugs in the core turned up while I wired this together, and both are fixed with tests. Arrays were getting flattened into the row under hydrateColumnNames: false, and an explicit param typeHint was getting dropped.

What works

I ran the whole Prisma Client query API against both engines on a live cluster. That's 179 tests. CRUD, aggregation and groupBy, every filter operator, pagination and cursors, select/include/omit, nested writes, relation filters, atomic number updates, JSON, Decimal/BigInt/DateTime, scalar arrays on Postgres, raw queries, and transactions. All of it passes.

The only gaps on MySQL are the ones Prisma already has on MySQL: mode: 'insensitive', createManyAndReturn, and disconnect/set on a required relation. You'd hit those same walls with the real mysql2 driver. None of it is specific to the Data API.

Migrations

Driver adapters only cover the runtime query path. Prisma's schema engine (migrate, db push, db pull) still wants a direct connection URL, and the Data API doesn't give you one. This is the same split Neon and PlanetScale have, where the adapter runs your queries and a direct URL runs your migrations.

There are two ways to handle it, both in the README. Point Prisma's migration URL at the Aurora cluster endpoint, which is the one I'd recommend and matches Neon's directUrl. Or generate the SQL offline with prisma migrate diff and apply it over the adapter.

Test plan

  • npm run test-ci (lint, build, 179 unit tests)
  • npm run test:int:orm:prisma (live pg + mysql suites, needs .env.local)
  • npm run test:int:orm:prisma:coverage (the full API coverage audit, both engines)

Adds data-api-client/compat/prisma — a drop-in Prisma 7 driver adapter so
Prisma Client runs over the Aurora RDS Data API for both engines, via
createPrismaPgAdapter / createPrismaMySQLAdapter.

The adapter is thin: it holds a core init() client and reuses its query
send/retry/result-formatting and beginTransaction/commit/rollback methods.
New code is confined to:
- prisma-types.ts: columnMetadata.typeName -> Prisma ColumnType mapping (pg + mysql)
- prisma-params.ts: $1/? placeholder rewrite, argType -> Data API param building,
  and the Postgres array ARRAY[...] rewrite (the Data API can't bind array params)
- prisma.ts: adapter/transaction/factory classes
- errors.ts: mapToPrismaError -> Prisma DriverAdapterError (lazy-requires the
  optional peer dep @prisma/driver-adapter-utils)

Two small core fixes surfaced and are covered by regression tests:
- results.ts: nest array-column cells instead of flattening them under
  hydrateColumnNames:false
- params.ts: honor an explicit param-level typeHint

Transactions map to the native Data API lifecycle; nested savepoints are
rejected. Migrations are documented, not implemented (driver adapters cover the
runtime path only — point Prisma's migration url at the Aurora endpoint, like
Neon/PlanetScale, or generate SQL offline and apply it over the adapter).
…(PG + MySQL)

Opt-in audits exercising the full Prisma Client query surface over the Data API
on both engines (179 tests: 99 pg, 80 mysql): CRUD, aggregation/groupBy, all
filter operators, pagination/cursor/distinct, select/include/omit, nested writes,
relation filters, atomic number updates, JSON, Decimal/BigInt/DateTime, scalar
arrays (pg), raw queries, and transactions.

Zero adapter bugs — the MySQL gaps (mode:insensitive, createManyAndReturn,
disconnect/set on required relations, scalar arrays) are standard Prisma-on-MySQL
behavior, identical to the native mysql2 driver.

Wired as opt-in scripts (test:int:orm:prisma:coverage[:pg|:mysql]) that generate
their own client; the default test:int:orm:prisma stays lean.
CLAUDE.md is listed under the AI-instruction-files block in .gitignore but was
still tracked, unlike WARP.md/.cursorrules/etc. Untrack it to match that policy;
the file stays on disk locally.
@jeremydaly jeremydaly force-pushed the feat/compat-prisma branch from 9efbd59 to 62ad504 Compare June 16, 2026 15:52
@jeremydaly jeremydaly merged commit 1ce74cf into main Jun 16, 2026
1 check passed
@jeremydaly jeremydaly deleted the feat/compat-prisma branch June 16, 2026 16:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant