Skip to main content
Prisma Documentation Docs

Search documentation

Type to search this documentation.

On this pageOverview

Port an existing app

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.

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

with
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 dev module.ts` and confirm every service boots with a local URL. Do not deploy; show me the diff first.

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.

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

title="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: '..' }),

});
title="next.config.ts"
export default { output: 'standalone' };

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

title="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.

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.

Build, then run the app locally before you deploy:

bun run build

bunx prisma dev module.ts
Bash
pnpm run build
pnpm prisma dev module.ts
Bash
yarn build
yarn prisma dev module.ts
Bash
npm run build
npx prisma 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.

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.

Suggest an edit

Propose a replacement for this page. The site team reviews it before applying any changes.

Export
Documentation menu