Prisma 8 is here.Read the docs

Port an existing app

Bring an app you already have to Prisma Composer by declaring it, keeping your server code and your build.

Bringing an existing app to Composer does not mean rewriting it. The server code you already have stays the server, and you add a service declaration around it. This page covers the three common cases.

Use with your agent

To delegate the port, run this from your project's root and hand the prompt to your coding agent:

Use with your agent
Use with your agent
Port this app to Prisma Composer.

1. Install the Composer skill with `npx skills add prisma/composer`, then read https://www.prisma.io/docs/composer/porting-an-app.md and follow it for this repository.
2. Survey the repo before changing anything and report back: every deployable server, its runtime (Node, Bun, or Next.js), its build command and entry file, every `process.env` read, and any database it connects to. Ask me about anything ambiguous.
3. Declare each server as a service with `compute()`, using the `node` or `nextjs` build adapter as appropriate, and compose them in a single `module.ts`.
4. Replace the `process.env` reads: the listen port becomes `service.port()` bound to `0.0.0.0`, config and credentials become fields of the service input schema, and anything another service provides becomes a typed dependency. Replace the URLs services use to reach each other with contracts.
5. If the app talks to Postgres, declare `postgres()` as a dependency and build the existing client from the injected `db.url` instead of a connection-string variable.
6. Verify with `npx tsc --noEmit`, then build and run `npx prisma@latest composer dev module.ts` and confirm every service boots with a local URL. Do not deploy; show me the diff first.

A Node.js or Bun service

Add a service.ts with compute({ name, deps, build: node({ module, entry }) }) pointing entry at your built server file, then make three changes to the server itself:

  1. Read the port from service.port(), never process.env, and bind 0.0.0.0:

    Bun.serve({ port: service.port(), hostname: '0.0.0.0', fetch: handler });
  2. Replace every other process.env read. Config and credentials become fields of the service's input schema. Anything another service provides becomes a dependency. If a value differs per stage (an app origin, an external URL), bind it with envParam. Bind a credential with envSecret.

  3. If it talks to Postgres: declare deps: { db: postgres() } and build your existing client (pg, Bun's SQL, whatever you use today) from the injected db.url instead of a connection-string env var. See Databases.

Your build must produce a self-contained entry file, with everything inlined except runtime built-ins. Keep your own build if it already does this. Otherwise, a one-line bun build --target=bun produces one. See Getting started.

A Next.js app

Use the nextjs build adapter instead of node. With output: 'standalone' set, next build is the whole build:

src/service.ts
import nextjs from '@prisma/composer/nextjs';
import { rpc } from '@prisma/composer/service-rpc';
import { compute } from '@prisma/composer-prisma-cloud';
import { apiContract } from '../api/contract.ts';

export default compute({
  name: 'web',
  deps: { api: rpc(apiContract) },
  build: nextjs({ module: import.meta.url, appDir: '..' }),
});
next.config.ts
export default { output: 'standalone' };

Add nextjsBuild() from @prisma/composer/nextjs/control to the deploy config's extensions:

prisma-composer.config.ts
import { defineConfig } from '@prisma/composer/config';
import { nextjsBuild } from '@prisma/composer/nextjs/control';
import { nodeBuild } from '@prisma/composer/node/control';
import { prismaCloud, prismaState } from '@prisma/composer-prisma-cloud/control';

export default defineConfig({
  extensions: [prismaCloud(), nodeBuild(), nextjsBuild()],
  state: prismaState(),
});

Add export const dynamic = 'force-dynamic' to any page or server action that calls service.load(). The runtime environment does not exist at build time, and Next.js will not re-read it for prerendered routes.

examples/storefront-auth in the Composer repository is a complete example of a ported app: a Next.js frontend calling a Bun API service that owns a Postgres.

More than one service

Port them into one module.ts and replace the URLs they used to reach each other with contracts. The payoff is that the calls between services become typed, and every environment (production, stages, tests) gets the wiring for free.

Verify the port

Build, then run the app locally before you deploy:

bun run build
bunx prisma@latest dev module.ts

Every service should appear in the startup output with a local URL. If a service fails at boot with a module-resolution error, its build left something un-inlined. Check that the entry file is self-contained.

Next steps

On this page