Skip to main content
skill Claude Code CX Codex Cursor GitHub Copilot

prisma-driver-adapter-implementation — Claude Code skill: Prisma 7 DB

Reference guide for implementing SQL adapters in Prisma ORM 7. Required for transaction handling, savepoint support, value mapping, and database error preservation.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add prisma/skills --skill prisma-driver-adapter-implementation -a claude-code
Open on GitHub

What prisma-driver-adapter-implementation does

The skill covers the contract for SqlDriverAdapter, Transaction, and adapter factories, plus critical rules: one connection per transaction, exact type mapping for columns and arguments, preserving original database errors, proper resource cleanup.

Includes code examples for queryRaw, executeRaw, executeScript, transaction and savepoint handling. Shows how to map results (int32/int64, decimal, bytes, date/time, UUID, JSON), execute migration scripts via a parser instead of naive semicolon splitting, and coordinate commit/rollback as lifecycle hooks without duplicate SQL.

Apply when adding a new database driver, modifying an adapter, or debugging transaction leaks and shadow-database failures. Requires the @prisma/driver-adapter-utils version bundled with your Prisma release.

What it helps with

  • implement a SQL adapter for a new database in Prisma 7
  • debug transaction leaks or connection issues
  • map column types and query arguments without data loss
  • add nested-transaction support via savepoint-s
  • capture and preserve original database errors

Example prompts for the agent

  • Show me the `SqlDriverAdapter` contract and lifecycle rules for commit and rollback
  • Help me implement `queryRaw` with argument and result type mapping
  • Explain how to enforce one connection per transaction and release it cleanly

How to install prisma-driver-adapter-implementation

1Skills CLI (Vercel)

npx skills add prisma/skills --skill prisma-driver-adapter-implementation -a claude-code

2Manually: put the files in place

~/.claude/skills/prisma-driver-adapter-implementation/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/prisma-driver-adapter-implementation/

From the same set10

The whole set →
prisma-client-api prisma Complete Prisma Client API reference for database queries, CRUD operations, and filtering. Triggers on findMany, create, update, delete, and $transaction. Claude Code CX Codex Cursor +1 389,500installs prisma-database-setup prisma A deprecated compatibility name for prisma-orm-setup, which handles Prisma setup and database connection repair. Claude Code CX Codex Cursor +1 388,400installs prisma-cli prisma Prisma ORM 7 CLI reference for AI agents. Guides client generation, schema migrations, and local database workflows while preventing accidental data loss. Claude Code CX Codex Cursor +1 386,800installs prisma-postgres prisma A deprecated compatibility name for prisma-postgres-setup. Use it only when explicitly invoked; new projects should select prisma-postgres-setup instead. Claude Code CX Codex Cursor +1 380,400installs prisma-postgres-setup prisma Provisions or connects a Prisma Postgres database and links it to your app. Useful for spinning up dev databases quickly or wiring connections in Vercel and v0. Claude Code CX Codex Cursor +1 374,900installs prisma-upgrade-v7 prisma Complete migration guide from Prisma ORM v6 to v7 with all critical changes: new generator, required driver adapters, ESM config, and client imports. Use when upgrading Prisma or hitting v7 errors. Claude Code CX Codex Cursor +1 374,800installs prisma-compute prisma Skill for deploying TypeScript apps to Prisma Compute via Prisma 8 CLI. Manage deployments, versions, environment variables, and custom domains from your editor. Claude Code CX Codex Cursor +1 370,000installs prisma-mongodb-upgrade prisma Decision guide for Prisma ORM MongoDB projects on v6 to navigate the lack of Prisma 7 support and evaluate moving to Prisma 8. Claude Code CX Codex Cursor +1 368,500installs

Similar

saga-orchestration Seth Hobson This skill designs sagas for distributed transactions and long-running workflows. Use it when 2PC is unavailable and failed steps need compensation. Claude Code CX Codex Cursor 10,700installs projection-patterns Seth Hobson Build read models from event streams with guidance on projection types and replay. Useful for CQRS read sides, materialized views, and search indexes. Claude Code CX Codex Cursor 10,500installs mcp-builder official anthropics This skill walks through building an MCP server in TypeScript or Python, from reading the protocol spec to writing tests and evaluation questions. Claude Code Claude.ai 130,949installs lark-im larksuite This skill lets an agent work with Lark IM messages, chats, files, and interactive cards. Use it when coding tasks need access to team conversations. Claude Code CX Codex Cursor +1 472,300installs lark-event larksuite Listens to Lark/Feishu events and streams them as NDJSON. Use it for bots, message processing, and long-running subscribers. Claude Code CX Codex Cursor +1 466,200installs caveman-discover JuliusBrussee Finds and labels every LLM workflow in your repository so Caveman Cloud breaks down spend by actual job rather than grouping everything into one bucket. Claude Code CX Codex Cursor +1 103,500installs migration JuliusBrussee Enforces reversible, compatibility-safe transitions for schema, data, and API updates. Useful whenever data loss or rollout downtime is unacceptable. Claude Code CX Codex Cursor +1 102,900installs caveman-setup JuliusBrussee Routes LLM API calls through the Caveman Cloud gateway to measure token costs without altering app behavior. Useful for tracking model spend across a repo. Claude Code CX Codex Cursor +1 102,500installs

Questions about prisma-driver-adapter-implementation

How do I install prisma-driver-adapter-implementation in Claude Code?

Run npx skills add prisma/skills --skill prisma-driver-adapter-implementation -a claude-code, then open ~/.claude/skills/prisma-driver-adapter-implementation/SKILL.md.

What does prisma-driver-adapter-implementation do?

Provides a reference for adapter contracts, priority rules, and code examples to implement and debug SQL adapters in Prisma ORM 7. Covers transactions, savepoint-s, type mapping, and error handling.

Do I need a specific Prisma version?

Yes, use the skill with the @prisma/driver-adapter-utils version installed by your target Prisma release. Driver adapters are a protocol boundary: type-compatible code can still corrupt values or break transactions.

Source text

SKILL.md · MIT
---
name: prisma-driver-adapter-implementation
description: Required reference for Prisma ORM 7 SQL driver adapter work. Use when implementing or modifying adapters, adding database drivers, or touching SqlDriverAdapter, Transaction, savepoint, result mapping, or DriverAdapterError behavior. Covers current transaction lifecycle, optional savepoint hooks, original database-error preservation, and verification.
license: MIT
metadata:
  author: prisma
  version: "7.9.1"
---

# Prisma SQL Driver Adapter Implementation

Use this guide with the exact `@prisma/driver-adapter-utils` version installed by the target Prisma release. Driver adapters are a protocol boundary: type-compatible code can still corrupt values, leak connections, or break transactions.

## When to Apply

- Implementing `SqlDriverAdapterFactory`, `SqlMigrationAwareDriverAdapterFactory`, `SqlDriverAdapter`, or `Transaction`
- Adding nested-transaction/savepoint support
- Mapping driver values, column metadata, bind arguments, or database errors
- Debugging `P2039`, transaction leaks, shadow-database failures, or adapter-specific query behavior

## Contract snapshot

```typescript
interface SqlDriverAdapterFactory extends AdapterInfo {
  connect(): Promise<SqlDriverAdapter>
}

interface SqlMigrationAwareDriverAdapterFactory extends SqlDriverAdapterFactory {
  connectToShadowDb(): Promise<SqlDriverAdapter>
}

interface SqlDriverAdapter extends AdapterInfo {
  queryRaw(query: SqlQuery): Promise<SqlResultSet>
  executeRaw(query: SqlQuery): Promise<number>
  executeScript(script: string): Promise<void>
  startTransaction(isolationLevel?: IsolationLevel): Promise<Transaction>
  getConnectionInfo?(): ConnectionInfo
  dispose(): Promise<void>
}

interface Transaction extends AdapterInfo {
  readonly options: { usePhantomQuery: boolean }
  queryRaw(query: SqlQuery): Promise<SqlResultSet>
  executeRaw(query: SqlQuery): Promise<number>
  commit(): Promise<void>
  rollback(): Promise<void>
  createSavepoint?(name: string): Promise<void>
  rollbackToSavepoint?(name: string): Promise<void>
  releaseSavepoint?(name: string): Promise<void>
}
```

`IsolationLevel` currently includes `READ UNCOMMITTED`, `READ COMMITTED`, `REPEATABLE READ`, `SNAPSHOT`, and `SERIALIZABLE`; validate what the concrete database supports.

## Priority rules

| Priority | Rule | Impact |
|----------|------|--------|
| CRITICAL | One dedicated connection per transaction | Prevents interleaving and leaks |
| CRITICAL | `commit`/`rollback` are lifecycle cleanup hooks | Prevents duplicate COMMIT/ROLLBACK |
| CRITICAL | Savepoints live on `Transaction`, not adapter-global depth | Makes nested scopes connection-local |
| CRITICAL | Preserve original database error code/message | Enables useful `P2039` fallback |
| HIGH | Map arguments and result metadata exactly | Prevents silent value corruption |
| HIGH | Shadow databases are isolated and always cleaned up | Makes Migrate safe |
| HIGH | Dispose only resources the adapter owns | Prevents shutting down caller-owned pools |

## Query implementation

`SqlQuery` contains `sql`, `args`, and parallel `argTypes`. Map each argument using both value and `ArgType`; do not discard type/arity information. Execute in the driver's array/tuple row mode so column order is stable.

```typescript
class ExampleQueryable {
  readonly provider = 'postgres' as const
  readonly adapterName = '@acme/adapter-example'

  constructor(protected readonly connection: DriverConnection) {}

  async queryRaw(query: SqlQuery): Promise<SqlResultSet> {
    try {
      const result = await this.connection.query({
        text: query.sql,
        values: query.args.map((value, index) =>
          mapArg(value, query.argTypes[index]),
        ),
        rowMode: 'array',
      })

      return {
        columnNames: result.fields.map((field) => field.name),
        columnTypes: result.fields.map(mapColumnType),
        rows: result.rows,
      }
    } catch (error) {
      throwAdapterError(error)
    }
  }

  async executeRaw(query: SqlQuery): Promise<number> {
    try {
      const result = await this.connection.execute(
        query.sql,
        query.args.map((value, index) => mapArg(value, query.argTypes[index])),
      )
      return result.rowsAffected ?? 0
    } catch (error) {
      throwAdapterError(error)
    }
  }
}
```

### Result mapping

Return `columnNames`, `columnTypes`, and `rows` with identical lengths/order. Map driver metadata to `ColumnTypeEnum` deliberately:

- signed integer widths to `Int32`/`Int64`; preserve 64-bit values without JS number truncation
- decimal/numeric to `Numeric` using the representation expected by Prisma
- binary to `Uint8Array`/`Bytes`
- date-only, time-only, and timestamp to `Date`, `Time`, and `DateTime`
- UUID, JSON, enum, arrays, and provider-specific unknown values to their explicit types
- unsupported native types to `DriverAdapterError({ kind: 'UnsupportedNativeDataType', type })`

Test `null`, empty arrays, array element types, big integers, decimals, byte arrays, JSON, dates, and user-defined/unknown native types.

### Script execution

`executeScript` must execute a migration script as the provider expects. Prefer the driver's native multi-statement/script facility or a real SQL parser. Naively splitting on `;` breaks functions, triggers, quoted strings, and dialect-specific blocks.

## Transaction protocol

`startTransaction` must acquire one dedicated connection, start the database transaction, apply the requested isolation level, and return a `Transaction` bound to that same connection. If setup fails, release it immediately.

```typescript
async startTransaction(level?: IsolationLevel): Promise<Transaction> {
  const connection = await this.pool.acquire()
  try {
    const tx = new ExampleTransaction(connection, () => connection.release())
    await tx.executeRaw({ sql: 'BEGIN', args: [], argTypes: [] })
    if (level) {
      await tx.executeRaw({
        sql: `SET TRANSACTION ISOLATION LEVEL ${validateLevel(level)}`,
        args: [],
        argTypes: [],
      })
    }
    return tx
  } catch (error) {
    connection.release(error)
    throwAdapterError(error)
  }
}
```

### Commit and rollback

Prisma coordinates the SQL `COMMIT`/`ROLLBACK` through `executeRaw`. The transaction object's `commit()` and `rollback()` methods are lifecycle hooks: detach listeners and release the dedicated connection exactly once. They must not issue a second SQL commit/rollback.

```typescript
class ExampleTransaction extends ExampleQueryable implements Transaction {
  readonly options = { usePhantomQuery: false }
  #closed = false

  constructor(connection: DriverConnection, private readonly release: () => void) {
    super(connection)
  }

  async commit() { this.finish() }
  async rollback() { this.finish() }

  private finish() {
    if (this.#closed) return
    this.#closed = true
    this.release()
  }

  async createSavepoint(name: string) {
    await this.control(`SAVEPOINT ${safeSavepoint(name)}`)
  }

  async rollbackToSavepoint(name: string) {
    await this.control(`ROLLBACK TO SAVEPOINT ${safeSavepoint(name)}`)
  }

  async releaseSavepoint(name: string) {
    await this.control(`RELEASE SAVEPOINT ${safeSavepoint(name)}`)
  }

  private async control(sql: string) {
    await this.executeRaw({ sql, args: [], argTypes: [] })
  }
}
```

Implement the optional savepoint methods only where the provider supports them. Validate/quote savepoint identifiers. For providers whose savepoints are intentionally no-ops, document and test that limitation.

Never keep transaction depth on the shared adapter. Parallel transactions make adapter-global depth incorrect; nested state belongs to the returned transaction connection and Prisma's savepoint calls.

## Error mapping

Wrap recognized driver failures in `DriverAdapterError`. Map known conditions to `MappedError` kinds such as constraint violations, authentication/reachability, missing table/column/database, timeouts, closed transactions, invalid input, value range, and write conflicts.

For database errors, preserve `originalCode` and `originalMessage` even when falling back to the provider-specific raw variant:

```typescript
import {
  DriverAdapterError,
  type Error as DriverAdapterErrorObject,
  type MappedError,
} from '@prisma/driver-adapter-utils'

function convertDriverError(error: DatabaseError): DriverAdapterErrorObject {
  return {
    originalCode: String(error.code),
    originalMessage: error.message,
    ...mapKnownOrRaw(error),
  }
}

function mapKnownOrRaw(error: DatabaseError): MappedError {
  if (error.code === '23505') {
    return { kind: 'UniqueConstraintViolation', constraint: parsedConstraint(error) }
  }
  return {
    kind: 'postgres',
    code: String(error.code ?? 'N/A'),
    severity: error.severity ?? 'N/A',
    message: error.message,
    detail: error.detail,
    column: error.column,
    hint: error.hint,
  }
}

function throwAdapterError(error: unknown): never {
  if (!isDatabaseError(error)) throw error
  throw new DriverAdapterError(convertDriverError(error))
}
```

Prisma uses preserved original details when an unmapped driver error becomes `P2039`. Do not replace every unknown exception with a fabricated `GenericJs` id; rethrow genuinely unexpected non-driver errors so programming bugs remain visible.

## Factory, ownership, and shadow database

- `connect()` returns a fresh usable adapter connection/pool wrapper.
- Track whether the factory created the pool. `dispose()` closes owned pools and only detaches listeners from caller-owned pools unless an explicit option transfers ownership.
- Implement `SqlMigrationAwareDriverAdapterFactory` only when `connectToShadowDb()` can create an isolated shadow database, connect to it, and drop it during disposal/failure cleanup.
- Never point the shadow adapter at the primary database. Quote generated identifiers and use cryptographically unique names.
- `getConnectionInfo()` should accurately report `schemaName`, `maxBindValues` when applicable, and `supportsRelationJoins`.

## Verification checklist

- [ ] Typecheck against the exact target `@prisma/driver-adapter-utils` version
- [ ] `queryRaw` preserves column order, types, nulls, and precision
- [ ] `executeRaw` reports affected rows correctly
- [ ] `executeScript` handles provider-specific multi-statement syntax
- [ ] Concurrent interactive transactions use distinct dedicated connections
- [ ] Success commits and releases once; failure rolls back and releases once
- [ ] Nested transaction tests exercise create/rollback/release savepoint hooks
- [ ] Unsupported isolation levels fail as `InvalidIsolationLevel`
- [ ] Known constraints map to structured errors
- [ ] Unmapped database errors retain original code/message and surface useful `P2039`
- [ ] Dispose ownership is tested for internal and external pools
- [ ] Shadow database creation, use, failure cleanup, and disposal are isolated
- [ ] Run Prisma Client integration/E2E tests, not only adapter unit tests

## Source references

- [Driver adapter interfaces](https://github.com/prisma/prisma/blob/v7/packages/driver-adapter-utils/src/types.ts)
- [PostgreSQL adapter transaction implementation](https://github.com/prisma/prisma/blob/v7/packages/adapter-pg/src/pg.ts)
- [PostgreSQL adapter error mapping](https://github.com/prisma/prisma/blob/v7/packages/adapter-pg/src/errors.ts)

© prisma · MIT · prisma/skills

See also

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor