Skip to content

Commit d88fca9

Browse files
feat: typed prisma.compute.ts compute config (#84)
## What Adds **`prisma.compute.ts`** — a typed, committed deploy configuration for Prisma Compute — and makes the entire `app` command surface config-aware. One config declares the deployable system (apps, roots, frameworks, ports, env, build settings); the CLI derives everything else, with flags as one-shot overrides and detection filling whatever is omitted. ```ts import { defineComputeConfig } from "@prisma/compute-sdk/config"; export default defineComputeConfig({ apps: { api: { root: "apps/api", framework: "hono", entry: "src/index.ts", httpPort: 8080 }, web: { root: "apps/web", framework: "nextjs", build: { command: "npm run build", outputDirectory: ".next/standalone" } }, }, }); ``` ```bash prisma-cli app deploy # deploys api and web, in order prisma-cli app deploy web # one target cd apps/api && prisma-cli app deploy # target inferred from cwd ``` ## Design rules - **Discovery is bounded:** nearest config from cwd up to the source root (`.git`/workspace markers); never escapes the repository; location-only discovery (no config evaluation) at CLI bootstrap. - **The config directory is the project directory:** `.prisma/local.json` pin, the state cache, and the `--db` schema scan anchor there; config-relative paths resolve from the config file so a committed config means the same thing from any cwd. - **One precedence everywhere:** `--app` > `PRISMA_APP_ID` > config target (positional `[app]` or cwd-inferred, deepest root wins) > remembered selection > inference. `--env` flags replace config env entirely. - **The config never selects Project, Branch, or production** — those stay explicit per the resource model. - **Bare `app deploy` against a multi-app config deploys the system** (declaration order, fail-fast with already-live/not-attempted reporting, per-app flags rejected, `--create-project` binds once). - **One framework detection** shared by deploy/build/run, driven by the capability registry in `@prisma/compute-sdk/config` — adding a framework is one registry entry plus its strategy. Covers **nextjs, nuxt, astro, hono, tanstack-start, bun** (matching the git-push path). For nuxt/astro the strategy owns the build, so a config `build` block is rejected (`BUILD_SETTINGS_UNSUPPORTED`) instead of silently ignored; with a build block and no declared framework, `app build` resolves the framework like deploy does before applying it. ## Also in this PR - **`prisma.app.json` removed:** never read or written. Leftovers that match inference warn for deletion; customized ones fail with `BUILD_SETTINGS_MIGRATION_REQUIRED` showing the exact `build` block — builds never change silently. - **Workspace build fixes:** package-manager detection walks up to the workspace root; ancestor `node_modules/.bin` dirs join the build PATH; Next.js standalone staging flattens **bun's isolated store** alongside pnpm's. - **`--db` is provision-only:** creates the branch database and wires `DATABASE_URL`/`DIRECT_URL`; never runs `db push`/`migrate deploy`/`generate`. Suggests the detected schema command plus `database connection create <id>` (env values are write-only on the platform by design). ⚠️ **This deliberately supersedes the schema-execution part of #82** (`resolvePrismaInvocation`, pinned `npx prisma@<x>` fallback): the rebase keeps #82's Next.js full-tree fallback work intact and removes only the schema-command execution it improved, since that execution path no longer exists. - **Packaging:** the config contract (types, framework registry, validation, discovery, jiti loading) is consumed from `@prisma/compute-sdk/config` (extracted in prisma/project-compute#86, released as 0.23.0) — single source of truth shared with the build-runner. The CLI keeps only its concerns: flag/config precedence merging and CliError presentation. There is no `@prisma/cli/config` export; configs import the helper from `@prisma/compute-sdk/config`, which the loader resolves without a local install. Publish-prep now carries `exports` into the published manifest (was silently dropping it). - **CI:** new `test.yml` workflow running the CLI suite and build on **ubuntu and windows**; new-code Windows audit done (platform-aware separators/delimiters throughout). - Removed the unused `c12` dependency. - Production-gate copy fixed (`prisma` → `prisma-cli`). ## New error codes `COMPUTE_CONFIG_INVALID`, `COMPUTE_CONFIG_TARGET_REQUIRED`, `COMPUTE_CONFIG_TARGET_UNKNOWN`, `BUILD_SETTINGS_MIGRATION_REQUIRED`, `BUILD_SETTINGS_UNSUPPORTED`. Retired: `APP_CONFIG_INVALID`. ## Verification - 470 tests (≈45 new: discovery boundaries, inference, deploy-all ordering and flag rejection, merge precedence, legacy migration classification, workspace package-manager walk-up, publish-prep exports). - Live-verified end to end: single-app zero-config deploys; an npm-workspaces monorepo (fully hoisted deps) deploying Hono and Next.js targets; deploy/build/run/logs/show from inside target roots; deploy-all; and a stock `bunx create-better-t-stack` scaffold (bun workspaces + catalogs + workspace imports) deployed with a 20-line config — which surfaced and fixed the bun-store staging bug. ## Out of scope / follow-ups - Config scaffolding (post-deploy offer / create-prisma template) — the biggest remaining DX gap. - `database` as config surface (designed, deliberately deferred; spec carries a reserved-growth-path note). - Cross-app URL references (web needing the server's deployed URL) — known first-contact friction. - Spec divergence with the platform team's `compute-branching.md` stages sketch (branch mapping in config) needs a deliberate reconciliation. JSON output shapes changed in beta: deploy-all aggregate result, `deploySettings.config` now `{ path: string|null, status: "config"|"inferred" }`, `branchDatabase.schema` removed.
1 parent dc06271 commit d88fca9

42 files changed

Lines changed: 4636 additions & 2426 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/test.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: Test
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
concurrency:
10+
group: test-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
test:
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
os:
19+
- ubuntu-latest
20+
- windows-latest
21+
runs-on: ${{ matrix.os }}
22+
permissions:
23+
contents: read
24+
25+
steps:
26+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
27+
with:
28+
persist-credentials: false
29+
30+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
31+
with:
32+
node-version: 24
33+
34+
- name: Enable pnpm
35+
shell: bash
36+
run: |
37+
corepack enable
38+
PNPM_VERSION="$(node -p 'const pm = require("./package.json").packageManager; const match = pm && pm.match(/^pnpm@(.+)$/); if (!match) throw new Error("packageManager must be pnpm@<version>"); match[1]')"
39+
corepack prepare "pnpm@${PNPM_VERSION}" --activate
40+
echo "PNPM_STORE_PATH=$(pnpm store path)" >> "$GITHUB_ENV"
41+
42+
- name: Cache pnpm store
43+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
44+
with:
45+
path: ${{ env.PNPM_STORE_PATH }}
46+
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
47+
restore-keys: |
48+
pnpm-store-${{ runner.os }}-
49+
50+
- name: Install dependencies
51+
run: pnpm install --frozen-lockfile
52+
53+
- name: Run CLI tests
54+
run: pnpm --filter @prisma/cli test
55+
56+
- name: Build CLI
57+
run: pnpm --filter @prisma/cli build

docs/product/command-spec.md

Lines changed: 115 additions & 35 deletions
Large diffs are not rendered by default.

docs/product/error-conventions.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,11 @@ These codes are the minimum stable set for the MVP:
170170
- `LOCAL_STATE_WRITE_FAILED`
171171
- `LOCAL_STATE_STALE`
172172
- `BRANCH_NOT_DEPLOYABLE`
173-
- `APP_CONFIG_INVALID`
173+
- `COMPUTE_CONFIG_INVALID`
174+
- `COMPUTE_CONFIG_TARGET_REQUIRED`
175+
- `COMPUTE_CONFIG_TARGET_UNKNOWN`
176+
- `BUILD_SETTINGS_MIGRATION_REQUIRED`
177+
- `BUILD_SETTINGS_UNSUPPORTED`
174178
- `FRAMEWORK_NOT_DETECTED`
175179
- `DEPLOYMENT_NOT_FOUND`
176180
- `NO_DEPLOYMENTS`
@@ -223,7 +227,11 @@ Recommended meanings:
223227
- `LOCAL_STATE_WRITE_FAILED`: the CLI could not save local Project binding state such as `.prisma/local.json` or the matching `.gitignore` entry; callers should fix directory permissions or filesystem state before retrying
224228
- `LOCAL_STATE_STALE`: local Project pin no longer matches platform data and continuing would be ambiguous
225229
- `BRANCH_NOT_DEPLOYABLE`: command tried to deploy to a non-deployable branch context
226-
- `APP_CONFIG_INVALID`: `prisma.app.json` is missing required build settings, has invalid JSON, or points outside the app root
230+
- `COMPUTE_CONFIG_INVALID`: `prisma.compute.ts` failed to load or validate
231+
- `COMPUTE_CONFIG_TARGET_REQUIRED`: a multi-app compute config needs an `[app]` target and none was given or inferred
232+
- `COMPUTE_CONFIG_TARGET_UNKNOWN`: the `[app]` target matches no configured app
233+
- `BUILD_SETTINGS_MIGRATION_REQUIRED`: a legacy `prisma.app.json` contains custom build settings that must move into the `build` block of `prisma.compute.ts`
234+
- `BUILD_SETTINGS_UNSUPPORTED`: a compute config `build` block targets a framework whose strategy owns its build (nuxt, astro)
227235
- `FRAMEWORK_NOT_DETECTED`: app deploy could not detect a supported Beta framework and no explicit framework/build type was provided
228236
- `DEPLOYMENT_NOT_FOUND`: requested deployment id does not exist
229237
- `NO_DEPLOYMENTS`: command resolved a branch or app but found no deployments

docs/product/output-conventions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ Examples:
338338
- `app deploy` should state the resolved target that matters in the current slice
339339
- first local `app deploy` binding should make the Project choice explicit before work begins
340340
- subsequent `app deploy` calls should use a compact target header such as `Deploying ./j1 to j1 / main / j1`
341-
- config-backed `app deploy` builds should show whether they created or used `prisma.app.json` before build starts: `Build Command` with its source when inferred, and `Output Directory` as a literal path such as `.next/standalone` rather than an opaque framework default label
341+
- config-backed `app deploy` builds should show the resolved build settings before build starts: `Build Command` and `Output Directory` with their sources (`prisma.compute.ts` or inference), `Output Directory` as a literal path such as `.next/standalone` rather than an opaque framework default label
342342
- `app logs` should state the deployment it resolved
343343
- `app list-deploys` should state which app or branch is being listed
344344

docs/product/resource-model.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ Rules:
3737

3838
- `project` is not the same thing as `app`
3939
- Public Beta does not read or write committed config files such as `prisma.config.ts` or `.prisma/settings.json` for project resolution
40-
- `.prisma/local.json` is a gitignored local pin/cache for Workspace and Project IDs; it is not a declarative repo config file
41-
- `prisma.app.json` is a committed app build-settings file only; it must not contain Workspace, Project, Branch, App, env, or secret resolution state
40+
- `.prisma/local.json` is a gitignored local pin/cache for Workspace and Project IDs; it is not a declarative repo config file. When a `prisma.compute.ts` is discovered (nearest config from the invocation directory up to the repository or workspace root), the pin and the CLI state cache (`.prisma/cli/state.json`) are read and written in the config file's directory; without a config they stay in the invocation directory
41+
- `prisma.compute.ts` is a committed deploy-defaults file; it must not contain Workspace, Project, Branch, env-secret, or credential resolution state
4242
- Project setup is explicit: users choose an existing Project or explicitly create a new one before remote work starts
4343
- `app deploy` may orchestrate Project setup, but it must not silently choose or create Project scope
4444
- everything under a project happens in a branch
@@ -104,7 +104,7 @@ Rules:
104104
- the runtime app service is scoped by branch in the platform model
105105
- the app may be selected or created as part of app deployment workflows
106106
- app selection is local CLI state when needed for the beta package
107-
- app build settings may live in `prisma.app.json` beside `package.json`; v1 fields are `buildCommand` and `outputDirectory`
107+
- app build settings live in the `build` block of `prisma.compute.ts` (`command`, `outputDirectory`); `prisma.app.json` is legacy and no longer read
108108

109109
### Deployment
110110

@@ -188,9 +188,9 @@ Rules:
188188
- first production deploy setup writes production `DATABASE_URL` and `DIRECT_URL` env vars before the App has a live deployment
189189
- database setup never overwrites an existing branch-scoped `DATABASE_URL`
190190
- production setup treats existing production `DATABASE_URL` or `DIRECT_URL` as BYO DB intent and leaves env vars unchanged
191-
- schema setup is sourced only from local code; the CLI does not clone or infer schema from another database
192-
- Prisma Next config (`prisma-next.config.*`) is preferred over `schema.prisma`
193-
- known non-Postgres Prisma sources are treated as unsupported for automatic Prisma Postgres setup
191+
- the CLI provisions the database and wires its env vars; it never runs schema, migration, or generate commands. A detected local Prisma schema source feeds only the suggested follow-up command the user runs themselves; the CLI does not clone or infer schema from another database
192+
- when detecting that local schema source for the suggestion, a Prisma Next config (`prisma-next.config.*`) is preferred over `schema.prisma`
193+
- a known non-Postgres Prisma source is treated as unsupported: it does not trigger automatic database prompting, and explicit `--db` is rejected
194194
- later production database configuration is managed through explicit environment-variable commands
195195

196196
## Relationships

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"lint": "biome check .",
1313
"lint:fix": "biome check . --write",
1414
"lint:skills": "node scripts/validate-skills.mjs",
15-
"prepare": "skills add ./skills --skill '*' --agent universal claude-code -y",
15+
"prepare": "node scripts/prepare-skills.mjs",
1616
"smoke:cli-nextjs": "node scripts/smoke-cli-nextjs-artifact.mjs",
1717
"test:skills": "node --test scripts/validate-skills.test.mjs",
1818
"test": "pnpm --filter @prisma/cli test",

packages/cli/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
"bin": {
77
"prisma-cli": "./dist/cli.js"
88
},
9+
"exports": {
10+
"./package.json": "./package.json"
11+
},
912
"files": [
1013
"dist",
1114
"README.md",
@@ -41,11 +44,10 @@
4144
},
4245
"dependencies": {
4346
"@clack/prompts": "^1.5.0",
44-
"@prisma/compute-sdk": "^0.22.0",
47+
"@prisma/compute-sdk": "^0.23.0",
4548
"@prisma/credentials-store": "^7.8.0",
4649
"@prisma/management-api-sdk": "^1.37.0",
4750
"better-result": "^2.9.2",
48-
"c12": "4.0.0-beta.5",
4951
"colorette": "^2.0.20",
5052
"commander": "^14.0.3",
5153
"dotenv": "^17.4.2",

0 commit comments

Comments
 (0)