1# Prisma TanStack Start
2
3Minimal TanStack Start app with Prisma Next queries, Prisma Postgres, and
4Prisma Compute managed by Alchemy.
5
6## What It Creates
7
8- A Prisma project.
9- The project-owned default `main` branch created by Prisma.
10- A Prisma Postgres database attached to `main` via `Prisma.Postgres(...)`.
11- A database connection with redacted connection strings.
12- A Prisma App.
13- A single Deployment built from TanStack Start's `.output` artifact.
14- Runtime env vars managed by `Prisma.Compute` in the branch environment and
15 snapshotted into each Deployment.
16- An optional Prisma App custom domain when `PRISMA_TANSTACK_DOMAIN` is set.
17- A Prisma Next contract in `src/prisma/contract.prisma`.
18- Generated Prisma Next artifacts in `src/prisma/contract.json` and
19 `src/prisma/contract.d.ts`.
20- A checked-in, versioned initial migration under `migrations/app/`.
21- An opt-in local seed script and server routes that query through
22 `@prisma-next/postgres/runtime` without returning database IDs or user data.
23
24Alchemy emits the current contract, transactionally applies checked-in Prisma
25Next migrations, and verifies the live schema as an explicit `Command.Exec`
26release step before Compute builds the artifact:
27
28```sh
29bun run db:migrate
30bun run build
31```
32
33`migration apply` is idempotent and the strict emit/apply/verify sequence runs
34on every deploy, so an unplanned contract change, database restore, or schema
35drift (including unexpected extra schema objects) fails the release instead of
36being hidden by local memo state. PostgreSQL lock waits are capped at 30 seconds,
37statements at five minutes, and Alchemy terminates the entire migration process
38group after six minutes. The direct database credential exists only in that
39command. Artifact packaging is pure and the
40Alchemy process's Prisma Management API credentials are excluded from both the
41migration subprocess and the application build. The production deployment
42receives only its pooled `DATABASE_URL`. Production deploys never seed or
43delete application data. Plan and review versioned migrations in source
44control, keep changes backward compatible with the currently promoted
45Deployment, and use expand/contract changes when a schema transition spans
46releases. The Deployment starts `server/index.mjs` on port `3000`.
47
48## Durable State Prerequisite
49
50This stack always uses `Cloudflare.state()`. Alchemy state is stored in a
51Cloudflare Worker backed by a Durable Object with embedded SQLite; its bearer
52token and encryption key live in Cloudflare Secrets Store. There is
53intentionally no local-state fallback. Alchemy does not currently ship a
54Prisma-hosted remote state store, so this example selects the built-in durable
55backend explicitly.
56
57Before the first deploy or local development session, make one Cloudflare
58account available to every trusted operator and CI runner that will deploy or
59destroy this stack, then bootstrap the state store once:
60
61```sh
62export CLOUDFLARE_ACCOUNT_ID="..."
63export CLOUDFLARE_API_TOKEN="..."
64bunx alchemy provider cloudflare bootstrap
65```
66
67Keep those Cloudflare credentials configured for every later dev, deploy, and
68destroy command. The default state-store Worker is shared across stacks and
69stages; Alchemy scopes this stack's records by stack name and stage.
70
71## Local Dev
72
73```sh
74export CLOUDFLARE_ACCOUNT_ID="..."
75export CLOUDFLARE_API_TOKEN="..."
76bun install
77bun run dev
78```
79
80`alchemy dev` starts a local Prisma Postgres with `@prisma/dev`, passes
81`DATABASE_URL` and `DIRECT_URL` for local migration convenience, runs
82`bun run db:setup`, and then starts Vite with `bun run dev:start`. Production
83runtime keeps the narrower single-credential contract described below.
84
85Open `http://localhost:3000`.
86
87If port 3000 is busy:
88
89```sh
90PRISMA_TANSTACK_DEV_PORT=3011 bun run dev
91```
92
93## Prisma Next Workflow
94
95```sh
96bun run emit # regenerate contract.json + contract.d.ts
97bunx prisma-next migration plan --name <change> # plan and review a migration
98bun run db:migrate # emit, transactionally apply, and verify the live schema
99bun run seed # opt-in demo data; never run by deploy
100bun run db:setup # migrate + demo seed, used by local dev
101```
102
103The Vite dev server also auto-emits the contract on edits. The explicit scripts
104remain the source of truth for deploys and CI so builds are reproducible.
105
106The runtime uses `pg`, so the example uses `connection.databaseUrl`
107to pass the pooled `postgres://` endpoint as `DATABASE_URL`. It explicitly
108omits `DIRECT_URL`, duplicate pooled variables, and Prisma resource IDs from the
109runtime environment. The schema command receives the direct endpoint only for
110the duration of contract application.
111
112## Deploy
113
114```sh
115export CLOUDFLARE_ACCOUNT_ID="..."
116export CLOUDFLARE_API_TOKEN="..."
117export PRISMA_SERVICE_TOKEN="..."
118export PRISMA_TANSTACK_APP="my-team-web-production"
119bun run deploy --stage production
120```
121
122The App name must be stable and unique within the Prisma workspace. The example
123defaults it from the Alchemy stage for local use; production and CI should set
124`PRISMA_TANSTACK_APP` to a deterministic environment-specific value. The
125Project name is provider-generated by default so interrupted creates can be
126recovered safely; set `PRISMA_PROJECT` only when an externally fixed Console
127name is required.
128
129The deploy output prints the Compute URL. Copy its `url` value before checking
130the app:
131
132```sh
133URL="https://your-app.prisma.build"
134```
135
136To attach a custom domain during deploy, set:
137
138```sh
139export PRISMA_TANSTACK_DOMAIN="app.example.com"
140bun run deploy --stage production
141```
142
143The stack output includes the custom domain status and DNS records to configure.
144
145## Check It
146
147```sh
148curl --fail-with-body --show-error "$URL/"
149curl --fail-with-body --show-error "$URL/api/health"
150```
151
152The health response should include:
153
154```json
155{
156 "ok": true,
157 "database": "ready",
158 "configuration": "ready"
159}
160```
161
162## Destroy
163
164```sh
165export CLOUDFLARE_ACCOUNT_ID="..."
166export CLOUDFLARE_API_TOKEN="..."
167export PRISMA_SERVICE_TOKEN="..."
168export PRISMA_TANSTACK_APP="my-team-web-production"
169bun run destroy --stage production
170```