Agent skill
prisma-7-docker-migrations
Run Prisma 7 migrations inside a multi-stage Docker production image. Use when: (1) `prisma migrate deploy` crashes with "Cannot resolve environment variable: DATABASE_URL" or "cannot find module" at container startup, (2) building a production Docker image that needs to run migrations before starting the server, (3) you copied only node_modules/prisma + node_modules/@prisma but the Prisma 7 CLI still fails with MODULE_NOT_FOUND at runtime, (4) Yarn 4 node-modules linker .bin/prisma symlink breaks after Docker COPY. Covers prisma.config.ts (Prisma 7), full node_modules copy requirement, and symlink recreation pattern.
Install this agent skill to your Project
npx add-skill https://github.com/yorch/claude-skills/tree/main/prisma-7-docker-migrations
SKILL.md
Prisma 7 in Docker Production Images
Problem
Prisma 7 changed how datasource URLs are configured and significantly expanded the CLI's runtime dependency closure. Two things that worked in Prisma 5/6 break silently in Prisma 7:
url = env("DATABASE_URL")inschema.prismais no longer valid — Prisma 7 moves this toprisma.config.tsviadefineConfig().- Selectively copying only
node_modules/prisma+node_modules/@prismais not enough — Prisma 7 CLI loads additional packages at runtime that aren't in those scopes.
Additionally, Yarn 4 node-modules linker creates .bin/prisma as a symlink. Docker COPY
dereferences symlinks, silently converting the symlink to a regular file at the wrong location,
breaking WASM engine loading.
Context / Trigger Conditions
- Prisma 7+ with a multi-stage Dockerfile
- Yarn 4 with
nodeLinker: node-modules - Container crashes at startup with any of:
PrismaConfigEnvError: Cannot resolve environment variable: DATABASE_URLError: Cannot find module '@prisma/config'Error: Cannot find module 'effect'Error: WASM file not foundor similar engine loading errors
prisma validatepasses locally but fails in the container
Root Causes
Root Cause 1: schema.prisma no longer holds the datasource URL
In Prisma 7, datasource db { url = env("DATABASE_URL") } was removed from schema.prisma.
The URL now lives in prisma.config.ts:
// packages/server/prisma.config.ts
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: { path: 'prisma/migrations' },
datasource: { url: env('DATABASE_URL') },
})
Root Cause 2: Prisma 7 CLI has a large non-bundled dependency closure
Prisma 7 CLI requires at runtime (beyond prisma and @prisma):
effectfast-checkpure-rand@prisma/config- Other transitive deps
Selective copying of node_modules/prisma + node_modules/@prisma misses these.
Root Cause 3: Docker COPY dereferences Yarn 4 .bin/ symlinks
In Yarn 4 node-modules linker, .bin/prisma is a symlink to
../prisma/build/index.js (relative path). Docker COPY follows the symlink and
copies the file content to the destination, preserving __dirname as the source
directory — not the destination. This breaks WASM loading which is relative to __dirname.
Solution
Step 1: Copy prisma.config.ts from the build stage
COPY --from=build-server /app/packages/server/prisma ./prisma
COPY --from=build-server /app/packages/server/prisma.config.ts ./prisma.config.ts
Step 2: Copy full node_modules (until a deps-prod stage is available)
# Prisma 7 CLI requires its full transitive dependency closure at runtime.
# TODO: Introduce a deps-prod stage (yarn workspaces focus server --production
# after adding @yarnpkg/plugin-workspace-tools) to reduce image size.
COPY --from=deps /app/node_modules ./node_modules
Step 3: Recreate the .bin/prisma symlink after COPY
# Yarn 4 .bin/prisma is a symlink that Docker COPY dereferences. Recreate it so
# __dirname resolves to prisma/build/ for correct WASM engine loading.
RUN ln -sf /app/node_modules/prisma/build/index.js /app/node_modules/.bin/prisma
Step 4: Add node_modules/.bin to PATH and update CMD
ENV PATH="/app/node_modules/.bin:$PATH"
CMD ["sh", "-c", "prisma migrate deploy && node server/index.mjs"]
Step 5: Move prisma from devDependencies to dependencies
In packages/server/package.json, move prisma to dependencies so the runtime
requirement is explicit and won't silently break if the install strategy changes:
{
"dependencies": {
"prisma": "7.x.x"
}
}
Complete Production Stage Example
# ── Production ───────────────────────────────────────────────────
FROM node:22-alpine AS production
WORKDIR /app
COPY --from=build-server /app/packages/server/dist ./server
COPY --from=build-web /app/packages/web/dist ./web
# Prisma: schema + migrations + config (Prisma 7 uses prisma.config.ts for datasource URL)
COPY --from=build-server /app/packages/server/prisma ./prisma
COPY --from=build-server /app/packages/server/prisma.config.ts ./prisma.config.ts
# Prisma 7 CLI requires its full transitive dependency closure at runtime.
# TODO: Introduce a deps-prod stage (yarn workspaces focus server --production
# after adding @yarnpkg/plugin-workspace-tools) to reduce image size.
COPY --from=deps /app/node_modules ./node_modules
# Yarn 4 .bin/prisma is a symlink that Docker COPY dereferences. Recreate it so
# __dirname resolves to prisma/build/ for correct WASM engine loading.
RUN ln -sf /app/node_modules/prisma/build/index.js /app/node_modules/.bin/prisma
ENV PATH="/app/node_modules/.bin:$PATH"
ENV NODE_ENV=production
EXPOSE 4000
CMD ["sh", "-c", "prisma migrate deploy && node server/index.mjs"]
Verification
Run the production image without DATABASE_URL — it should fail with a clear
Prisma config error (not a Node.js module error):
docker build -t test:local .
docker run --rm test:local
# Expected: PrismaConfigEnvError: Cannot resolve environment variable: DATABASE_URL
# NOT: Error: Cannot find module '...'
If you see Cannot find module, the dependency closure is still incomplete.
Future Optimization (Image Size)
The full node_modules copy significantly inflates the image. The correct long-term fix:
- Add
@yarnpkg/plugin-workspace-toolsto Yarn plugins - Add a
deps-prodstage:RUN yarn workspaces focus server --production - Copy only Prisma-required packages from that stage
Until then, the full copy is the reliable approach.
Notes
- Prisma 7's
.tsconfig files are executed by the CLI's internal TypeScript loader —tsxis NOT required in the production image - The
restart: unless-stoppedDocker compose policy will cause a crash-loop ifprisma migrate deployfails — set astart_periodon your healthcheck and monitor logs prismashould be independencies, notdevDependencies, since it runs at container startup
References
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
typescript-unknown-jsx-expression
Fix TypeScript error "Type 'unknown' is not assignable to type ReactNode" when using Record<string, unknown> values directly in JSX && short-circuit expressions. Use when: (1) JSX expression {someObj.field && <Component />} fails with TS2322, (2) Reading from a JSON or untyped object via bracket notation in JSX conditionals, (3) Values typed as unknown appear in JSX even when wrapped in String() or guarded with truthiness checks. Fix: use !! to coerce to boolean before the && operator.
gha-docker-publish
ALWAYS invoke this skill before writing any GitHub Actions workflow that builds or pushes Docker images — it contains specific opinionated patterns that produce secure, reliable workflows and that you cannot reliably guess. The conventions it enforces include: (1) datetime+SHA image tags in YYYYMMDDHHMMSS_sha format for unambiguous build traceability, (2) a `workflow_dispatch` boolean `push` input that defaults to `false` (safe dry-run by default — a common mistake is using `type:choice` with `dry_run` inversion instead), (3) a `publish-docker` PR label gate that lets CI validate builds on PRs without pushing, (4) conditional `latest` tag using `enable={{is_default_branch}}` (never hardcoded `enable=true`), (5) GHA layer cache with `mode=max` for maximum rebuild speed, (6) no inline `${{ github.sha }}` in `run:` scripts (security hardening), (7) dual-registry login and push patterns when publishing to both GHCR and a private registry. Use this whenever the user asks to: set up GHCR publishing, add a docker-publish.yml workflow, add layer caching to Docker CI, configure datetime/SHA image tags, add a manual build-only dispatch trigger, push to multiple registries, or build Docker images on PRs.
code-changes-review
Perform a comprehensive code review of current uncommitted changes in a git repository. Analyzes for bugs, security vulnerabilities, best practices, DRY violations, code smells, performance issues, and areas of improvement. Use when: review changes, code review, check my code, review diff, pre-commit review, PR review, quality check. Works with any language or framework.
rails-auto-assigned-field-validation
Fix for Rails models where validates :field, presence: true causes ALL creates to fail when the field is set by a before_create callback. Use when: (1) validates :number, presence: true is added to a model that uses before_create to auto-assign a sequence number, (2) model creates silently fail with "number can't be blank", (3) auto-generated fields (number, slug, token) fail presence validation despite being set in callbacks. Root cause: before_create runs AFTER validations. Fix: change before_create to before_validation on: :create.
app-docker-deploy-with-traefik
Generate Docker and Traefik deployment configurations for any application (Node.js, Python, Go, Rust, Java). Creates Dockerfile, docker-compose.yml, docker-compose.for-traefik.yml overlay, and .env.sample with production best practices. Use when: dockerize app, containerize, add Docker, deploy with Traefik, reverse proxy setup, HTTPS/SSL, Let's Encrypt certificates, production deployment, docker-compose setup. Requires: Docker, docker-compose.
edit-article
Edit and improve articles by restructuring sections, improving clarity, and tightening prose. Use when user wants to edit, revise, or improve an article draft.
Didn't find tool you were looking for?