Files
doodle-store/apps/server/.agents/skills/prisma-compute/references/app-framework-builds.md
T

4.9 KiB

app-framework-builds

Each framework deploys through a build adapter in its service.ts that points at the output your own build produced.

Priority

CRITICAL

Why It Matters

Neither prisma deploy nor the deploy action detects a framework or runs a build. The service declaration names the built output, and a mismatch between it and what the build writes fails at assemble time or at boot. There are no framework keys any more (--framework nextjs and similar belonged to the removed CLI).

Adapters

Adapter Import Use for
node({ module: import.meta.url, entry }) @prisma/composer/node One self-contained ESM file with every dependency inlined except runtime built-ins (bun, bun:*, node:*)
node({ module: import.meta.url, dir, entry }) @prisma/composer/node A built directory copied as-is; entry is a file inside dir
nextjs({ module: import.meta.url, appDir }) @prisma/composer/nextjs A Next.js app built with output: "standalone"; add nextjsBuild() to the composer extensions
dependencies: "external" on either node() form @prisma/composer/node A build that leaves packages as imports. The deploy traces entry and stages the installed packages it imports, which can take minutes. Composer 0.29.0 and later

Paths are relative to the service module. With the default dependencies: "bundled", the deploy copies only what the build produced and never ships the project's node_modules, for a single file and for a dir build alike, so a package left as an import fails at boot with Cannot find package. Bundle it, or set dependencies: "external". A dir tree must contain no symlinks and entry must not leave dir. Two services in one package need two separate builds, one per entry.

Per Framework

The shapes create-prisma 0.14.1 generates, with service.ts at the project root:

Framework Build script build: in service.ts Requirements
Hono, Elysia, NestJS, plain server Bundle to one file (bun build src/index.ts --target=bun --outfile dist/server.mjs, or tsdown bundling every non-built-in dependency) node({ module: import.meta.url, entry: "./dist/server.mjs" }) The entry starts the HTTP server itself
Next.js next build nextjs({ module: import.meta.url, appDir: "." }) output: "standalone" in next.config.*; nextjsBuild() in prisma.config.ts
Nuxt nuxt build node({ module: import.meta.url, dir: "./.output", entry: "server/index.mjs" }) Default Nitro Node server preset
TanStack Start vite build node({ module: import.meta.url, dir: "./.output", entry: "server/index.mjs" }) nitro() from nitro/vite in the Vite plugins
Astro astro build node({ module: import.meta.url, dir: "./dist", entry: "server/entry.mjs", dependencies: "external" }) output: "server", adapter: node({ mode: "standalone" }) from @astrojs/node. The adapter leaves packages as imports, so Composer 0.29.0 and later need dependencies: "external"; create-prisma 0.14.x pins Composer 0.28.0 and omits it
SvelteKit vite build node({ module: import.meta.url, dir: "./build", entry: "index.js" }) @sveltejs/adapter-node, with ssr: { noExternal: true } in vite.config.ts so the build inlines packages; without it, add dependencies: "external"
Turborepo turbo run build node({ module: import.meta.url, entry: "./apps/server/dist/server.mjs" }) One compute() per deployable app

Verify the actual output path after a local build before writing entry or dir.

Host and Port

The runtime exports the reserved port as PORT and sets HOST to 0.0.0.0 when it is unset. Code you write reads service.port() and binds 0.0.0.0. Framework servers that read PORT themselves (Next.js standalone, Nitro, Astro's Node adapter, SvelteKit's Node adapter) work without changes. Never set HOST or HOSTNAME to localhost or 127.0.0.1 in deploy env.

// Elysia
app.listen({ port: service.port(), hostname: "0.0.0.0" });

// NestJS
await app.listen(service.port(), "0.0.0.0");

Next.js Pages That Read the Service

A page, route handler, or server action that calls service.load() or service.input() needs export const dynamic = "force-dynamic". The runtime environment does not exist at build time, and Next.js does not re-read it for prerendered routes.

Bad

build: node({ module: import.meta.url, entry: "./src/index.ts" }),

The entry is source, not a self-contained build. Imports from node_modules fail at boot.

Good

build: node({ module: import.meta.url, entry: "./dist/server.mjs" }),

with "build": "bun build src/index.ts --target=bun --outfile dist/server.mjs".

References