Subchapter 3.1
references/app-composer-setup.mdMarkdown8 KBView on GitHub
Compute deploys only Prisma Composer apps: a root module, one service declaration per server, and a composer section in prisma.config.ts.
CRITICAL
prisma deploy takes a module file, not a framework name or a config file. Without module.ts, a compute() service, and the composer config section, there is nothing to deploy. This file covers the minimum an agent needs. For contracts between services, input schemas, modules, and testing, use the prisma-composer-core-concepts skill and the Composer docs (opens in a new tab).
engines.node is ^22.18.0 || ^24.11.0 || >=26.0.0 since Composer 0.30.0). Composer loads the .ts entry directly; older versions stop at ERR_UNKNOWN_FILE_EXTENSION.bun build --target=bun is the simplest way to produce the single-file entry a service needs.npm install @prisma/composer @prisma/composer-prisma-cloud
npm install -D prisma
npx prisma skills sync@prisma/composer pins its own effect version; do not add a different effect to the app. See debug-deploy-failures.md if prisma.config.ts fails to evaluate.
// src/server.ts
import service from "./service.ts";
Bun.serve({
port: service.port(),
hostname: "0.0.0.0",
fetch: () => new Response("ok"),
});// src/service.ts
import node from "@prisma/composer/node";
import { compute } from "@prisma/composer-prisma-cloud";
export default compute({
name: "web",
deps: {},
build: node({ module: import.meta.url, entry: "../dist/server.mjs" }),
});// module.ts
import { module } from "@prisma/composer";
import web from "./src/service.ts";
export default module("my-app", ({ provision }) => {
provision(web);
});// prisma.config.ts
import { defineConfig as composer } from "@prisma/composer/config";
import { nodeBuild } from "@prisma/composer/node/control";
import { prismaCloud, prismaState } from "@prisma/composer-prisma-cloud/control";
import { definePrismaConfig } from "prisma/config";
export default definePrismaConfig({
composer: composer({
extensions: [prismaCloud({ region: "us-east-1" }), nodeBuild()],
state: prismaState(),
}),
});And a build script in package.json that produces the file entry points at:
{
"scripts": {
"build": "bun build src/server.ts --target=bun --outfile dist/server.mjs"
}
}Rules:
entry and dir resolve relative to the service module (module: import.meta.url), not the project root.composer section accepts only extensions and state. Add nextjsBuild() from @prisma/composer/nextjs/control when a service uses the nextjs adapter.prisma.config.ts is read by the CLI only; app code never imports it. A separate prisma-composer.config.ts is refused..ts extensions and enable allowImportingTsExtensions in tsconfig.json.The first deploy creates the project and needs a region. Set prismaCloud({ region }) or PRISMA_REGION; the config value wins when both are set. Without either, the deploy stops with project "<name>" does not exist yet and no deploy region is configured. Once the project exists it keeps its region, and stages inherit it.
Region ids: us-east-1, us-west-1, eu-west-3, eu-central-1, ap-northeast-1, ap-southeast-1.
module("my-app", ...)) becomes the project name and may contain hyphens. deploy --name <name> overrides it.compute({ name }) and provision() ids allow [A-Za-z0-9] only. A hyphenated id passes tsc and then fails at load. The platform rejects provision ids shorter than three characters, so name a database database, not db.Declare the database as a dependency of the service and provision it in the module that owns it. The service reads the value with service.load().
// src/service.ts
import node from "@prisma/composer/node";
import { compute, rawPostgres } from "@prisma/composer-prisma-cloud";
export default compute({
name: "api",
deps: { db: rawPostgres() },
build: node({ module: import.meta.url, entry: "../dist/server.mjs" }),
});// module.ts
import { module } from "@prisma/composer";
import { rawPostgres } from "@prisma/composer-prisma-cloud";
import api from "./src/service.ts";
export default module("my-app", ({ provision }) => {
const db = provision(rawPostgres({ name: "database" }));
provision(api, { deps: { db } });
});// src/server.ts
import { SQL } from "bun";
import service from "./service.ts";
const { db } = service.load();
const sql = new SQL({ url: db.url, max: 1, idleTimeout: 10 });rawPostgres() comes from the package root and delivers { url }. You own the client and the schema; the deploy runs no migrations for it.postgres(contract) comes from @prisma/composer-prisma-cloud/orm, together with dataContract. It delivers { url, client } with a client typed by your Prisma ORM data contract, and the deploy applies the committed migrations/ before the service starts. Every schema change goes through prisma contract emit and prisma migration plan first. See Databases (opens in a new tab).postgres is not exported from the package root in 0.28.0, and postgres() with no argument does not declare a plain database. Use rawPostgres() for that.Buckets work the same way: bucket() from the package root, delivering { url, bucket, accessKeyId, secretAccessKey }.
Composer services do not read process.env. Declare the service’s configuration as an input schema, and bind each field at provision() to a literal, envParam("NAME"), or envSecret("NAME"). The named values live in the stage’s platform environment variables (project env). A deploy copies a missing name from the deploying shell and fails early, naming the variable, when neither has it. See Service input (opens in a new tab).
prisma.compute.ts field | Composer equivalent |
|---|---|
app.name / apps.<key> | compute({ name }); the root module name is the project name |
framework, build.command | Your own build script, run before deploy |
entry, build.outputDirectory, build.entrypoint | node({ module, entry }) or node({ module, dir, entry }) pointing at built output, or nextjs({ module, appDir }) |
httpPort | Removed. Listen on service.port() |
env file | Platform env vars through project env add --file, bound with envParam/envSecret; a database becomes a declared dependency |
region | prismaCloud({ region }), used only when the first deploy creates the project |
apps (monorepo) | One compute() per deployable app, all provisioned in one module.ts |
--branch <name> on deploy | deploy --stage <name> |
Then delete prisma.compute.ts, the compute:deploy script, and the @prisma/compute-sdk dev dependency if nothing else imports it. .prisma/cli/state.json from the old CLI is no longer used.
// prisma.compute.ts
import { defineComputeConfig } from "@prisma/compute-sdk/config";
export default defineComputeConfig({
app: { framework: "hono", entry: "src/index.ts", httpPort: 8080 },
});No current command reads this file.
module.ts, src/service.ts, and the composer section of prisma.config.ts as shown above, with a build script that writes the file entry names.