Skip to content

feat(prisma): add Effect-native Prisma ORM v8 support - #1198

Merged
sam-goodwin merged 19 commits into
mainfrom
claude/prisma-v8-rc-plan-4f746c
Sep 21, 2026
Merged

sam-goodwin merged 19 commits into
mainfrom
claude/prisma-v8-rc-plan-4f746c

Conversation

@sam-goodwin

@sam-goodwin sam-goodwin commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

Add Prisma ORM v8 with TypeScript-first and PSL-first contracts sharing an Effect-native Postgres query runtime. Prisma remains an optional peer.

TypeScript-first

Use Prisma's native builders without generated application imports:

import { defineContract } from "alchemy/Prisma/ORM";
import { Postgres } from "alchemy/Prisma/ORM/Postgres";
import { makeSchemas } from "alchemy/Prisma/ORM/Schema";

const contract = defineContract({}, ({ field, model }) => ({
  models: {
    User: model("User", {
      fields: { id: field.int().id(), email: field.text() },
    }),
  },
}));

const db = yield* Postgres(connectionString, { contract });
const users = yield* db.orm.public.User.select("id", "email").all();
const schemas = makeSchemas(contract);

PSL-first

Register withEffect on Prisma's ORM configuration and run alchemy prisma generate (or --watch). Keep contract.psl authoritative and import thin generated bindings:

import { makeDatabase } from "./prisma/generated/client.ts";
import { schemas } from "./prisma/generated/schemas.ts";

const db = yield* makeDatabase(connectionString);
const users = yield* db.orm.public.User.select("id", "email").all();
  • Generate client bindings, standalone Effect row schemas, or both. Schema modules do not load the query client; unsupported codecs require explicit mappings. These validate scalar rows, not mutation inputs or relation-expanded results.
  • Keep contract emission and migration planning/application separate from runtime queries. Wrap query terminals, prepared statements, streams, and transactions in Effects with typed errors and per-execution connection cleanup.
  • Support single-table and multi-table variant queries, including variant-owned relations and scalar projections. Keep scalar include reducers restricted to to-many relations.
  • Preserve rc.11 native-contract inference through a declaration-only compatibility adapter; runtime builders remain Prisma's original functions. Upstream fix: prisma/orm#30342.
  • Add runnable TypeScript-first and PSL-first Cloudflare/Neon examples. Disable Hyperdrive query caching so reads immediately reflect writes while retaining connection pooling.
  • Document both workflows and flatten Prisma/SQL API-reference navigation.

Adds Prisma.Contract + Prisma.Migrate deploy-time resources, the
alchemy/Prisma/ORM/Postgres runtime binding (per-execution pool,
workerd-safe), /sql/prisma docs, and the cloudflare-neon-prisma
example. Pinned to 8.0.0-rc.1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@alchemy-version-bot

alchemy-version-bot Bot commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

Install the packages built from this commit:

Alchemy

alchemy

bun add https://pkg.ing/alchemy/838762a

@alchemy.run/better-auth

bun add https://pkg.ing/@alchemy.run/better-auth/838762a

@alchemy.run/cloudflare-runtime

bun add https://pkg.ing/@alchemy.run/cloudflare-runtime/838762a

@alchemy.run/frontend-frameworks

bun add https://pkg.ing/@alchemy.run/frontend-frameworks/838762a

@alchemy.run/node-utils

bun add https://pkg.ing/@alchemy.run/node-utils/838762a

@alchemy.run/pr-package

bun add https://pkg.ing/@alchemy.run/pr-package/838762a

@alchemy.run/floci

bun add https://pkg.ing/@alchemy.run/floci/838762a

Distilled

@distilled.cloud/core

bun add https://pkg.ing/@distilled.cloud/core/c7b11bc

@distilled.cloud/aws

bun add https://pkg.ing/@distilled.cloud/aws/c7b11bc

@distilled.cloud/axiom

bun add https://pkg.ing/@distilled.cloud/axiom/c7b11bc

@distilled.cloud/cloudflare

bun add https://pkg.ing/@distilled.cloud/cloudflare/c7b11bc

@distilled.cloud/hetzner

bun add https://pkg.ing/@distilled.cloud/hetzner/c7b11bc

@distilled.cloud/neon

bun add https://pkg.ing/@distilled.cloud/neon/c7b11bc

@distilled.cloud/planetscale

bun add https://pkg.ing/@distilled.cloud/planetscale/c7b11bc

sam-goodwin and others added 8 commits August 13, 2026 18:59
Queries are now Effects: db.orm chains prisma-next's Collection via a
path-replaying proxy (lazy, re-runnable, typed rows preserved through
include/select), db.sql plans run through an Effect executor
(execute/stream), and db.transaction commits/rolls back by exit status
with a typed PrismaRollbackError. Errors surface as tagged
PrismaQueryError (sqlState/constraint), PrismaConnectionError
(transient), and PrismaError. No upstream changes — built entirely on
prisma-next's public seams; db.use remains the escape hatch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Prisma 8's headline authoring form is the defineContract TS DSL, not
PSL. The example, docs, and PR walkthrough now lead with it (PSL stays
supported — the integration is authoring-agnostic). Works around an
rc.1 bug where TS-authored emits write unpublished @internal/* import
specifiers into contract.d.ts: Prisma.Contract rewrites them to the
public @prisma/orm-postgres/* subpaths after emit (no-op for PSL),
failing actionably on unmapped specifiers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Each SQL integrity violation gets its own tag (Unique/ForeignKey/
NotNull/CheckViolationError via driver-normalized SQLSTATE 23xxx), and
prisma-next's structured codes split by category into PrismaOrmError /
PrismaRuntimeError with an autocompleting open-union code field.
Tag-per-category rather than tag-per-code: SQLSTATEs and categories
are stable across RCs, individual codes churn. PrismaError remains
only for truly unclassified throws.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Errors live in the Prisma namespace, so the prefix was noise:
Prisma.UniqueViolationError, Prisma.QueryError, Prisma.OrmError,
Prisma.RuntimeError, Prisma.ConnectionError, Prisma.RollbackError,
Prisma.CliError (deploy-time), Prisma.UnknownError (fallback),
Prisma.ClientError (union), Prisma.ErrorCode. Tags renamed to match
(e.g. "Prisma.UniqueViolationError").

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same linguist-generated marks prisma-next init scaffolds; migration.ts
stays unmarked as the placeholder editing surface.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resolves the pnpm-catalog migration (bun workspaces -> pnpm named
catalogs), the Prisma Providers.ts restructure (per-resource
ProviderLayer.dual replaced the dev/live implementationLayer switch),
and drops the retired bun.lock.

Claude-Session: https://claude.ai/code/session_01QVa7UvSQr7Y5xBqXMFbmc2
The `prisma-next` bin is retired (rc.2) and the config hard-cut landed in
rc.4: the unified `prisma` CLI mounts the ORM commands and reads only
`prisma.config.ts` in the engine envelope shape.

- `Prisma.Contract` / `Prisma.Migrate` shell `prisma contract emit`,
  `prisma migration plan`, and `prisma db migrate` (was `prisma-next
  migrate`), resolving the bin from the optional `prisma` peer.
- `--json` is now a newline-delimited event stream closed by a
  `{ kind: "result", envelope }` document; the runner parses that
  envelope and maps `envelope.error` (`code`/`summary`/`why`/`meta`,
  `DRIVER.CONNECTION_FAILED`) onto `Prisma.CliError`.
- Runtime: row plans execute through `runtime().query(plan)` (rc.2 split
  `query` from `execute`), transaction lanes bind `orm({ runtime: txn })`,
  and ORM pagination is `.limit()` / `.offset()` (rc.7 rename).
- Config files move to `prisma.config.ts` with
  `definePrismaConfig({ orm: ormConfig({ ... }) })`; fixtures, example,
  and docs follow. Contract artifacts + migration packages regenerated.
- The example's `createdAt` takes the text representation
  (`field.temporal.createdAtString()`): rc.6 made temporal columns decode
  to `Temporal.*`, which workerd has no implementation for.
- Emitted `contract.d.ts` files are checked in (they leak unpublished
  `@internal/*` specifiers the resource rewrites) so a clean checkout
  typechecks without running a deploy.

Claude-Session: https://claude.ai/code/session_01QVa7UvSQr7Y5xBqXMFbmc2
The example was never listed in the root tsconfig references, so `tsc -b`
never compiled it — and it did not compile:

- `import type { Contract } from "./prisma/contract.d.ts"` resolved to the
  contract *source* (`contract.ts`) next to it. Emit now writes to
  `src/prisma/generated/`, matching the test fixtures.
- `field.id.uuidv7String()` types the id as a branded `Char<36>`, so an id
  parsed out of a URL cannot be passed to `where({ id })`. Native uuid
  columns (`field.id.uuidv7Native()` / `field.uuidNative()`) keep the TS
  type a plain string.
- `prisma.config.ts` and the TypeScript-authored contract source infer
  types that cannot be named portably from this project (TS2883); both are
  loaded by the prisma CLI under its own toolchain, so they are excluded
  the same way the test fixtures' configs are.

Claude-Session: https://claude.ai/code/session_01QVa7UvSQr7Y5xBqXMFbmc2
@sam-goodwin

Copy link
Copy Markdown
Contributor Author

Automated fix: addressed CI failure in Check (docs:check-jsdoc on Prisma.Contract / Prisma.Migrate).

…lan-4f746c

# Conflicts:
#	packages/alchemy/package.json
#	packages/alchemy/src/Prisma/Providers.ts
#	pnpm-lock.yaml
#	pnpm-workspace.yaml
@alchemy-version-bot

alchemy-version-bot Bot commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

Install the packages built from this commit:

alchemy

pnpm install https://pkg.alchemy.run/alchemy/pr:1198:745789f
@alchemy.run (6)
pnpm install https://pkg.alchemy.run/@alchemy.run/better-auth/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@alchemy.run/cloudflare-runtime/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@alchemy.run/frontend-frameworks/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@alchemy.run/node-utils/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@alchemy.run/floci/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@alchemy.run/pkg/pr:1198:745789f
@distilled.cloud (14)
pnpm install https://pkg.alchemy.run/@distilled.cloud/core/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@distilled.cloud/acme/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@distilled.cloud/aws/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@distilled.cloud/axiom/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@distilled.cloud/cloudflare/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@distilled.cloud/fly-io/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@distilled.cloud/github/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@distilled.cloud/hetzner/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@distilled.cloud/neon/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@distilled.cloud/prisma/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@distilled.cloud/planetscale/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@distilled.cloud/railway/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@distilled.cloud/stripe/pr:1198:745789f
pnpm install https://pkg.alchemy.run/@distilled.cloud/zerossl/pr:1198:745789f

Published Sep 21, 2026, 5:45 AM UTC. Expires Sep 28, 2026, 5:45 AM UTC, extended while this pull request is open.

@sam-goodwin
sam-goodwin marked this pull request as draft September 18, 2026 03:26
@sam-goodwin sam-goodwin changed the title feat(prisma): Prisma ORM v8 (prisma-next) support feat(prisma): add Effect-native Prisma ORM v8 support Sep 18, 2026
@sam-goodwin
sam-goodwin marked this pull request as ready for review September 20, 2026 00:47
…lan-4f746c

# Conflicts:
#	pnpm-lock.yaml
#	website/public/llms.txt
@sam-goodwin
sam-goodwin merged commit 3b82f22 into main Sep 21, 2026
8 checks passed
@sam-goodwin
sam-goodwin deleted the claude/prisma-v8-rc-plan-4f746c branch September 21, 2026 05:51
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.

3 participants