DEV Community

whchi
whchi

Posted on

Prisma-Docker Problem: Why `migrate deploy` Installs Binaries Again

If you use pnpm and Prisma inside a multi-stage Docker build, you might see a strange thing: Prisma tries to download its binary files (like linux-musl-openssl-3.0.x) again, even though you ran pnpm prisma generate in an earlier stage.

This is a common issue. It is not a mistake in your code. It is a problem with how Prisma checks its files and how Docker handles time when copying files.

ðŸŠĪ The Problem: The Timestamp Trap

Prisma is built to check if its Client is old (or "stale").

  • Prisma's Rule: Prisma checks the last modified time (timestamp) of two important files:
    1. Your schema.prisma file (the source code).
    2. The generated Prisma Client in node_modules/.prisma/client.
  • The Decision: If the schema.prisma file's time is newer than the Client's time, Prisma decides that the Client is old.
  • The Action: It automatically runs prisma generate again. This action includes checking and downloading the binary files you listed in binaryTargets.

How Docker Creates This Problem

  1. Builder Stage (Time T1 - Old Time): You run pnpm prisma generate. The generated Client gets a timestamp of T1.
  2. Runner Stage (Time T2 - New Time):
    • You copy the Client from the builder: COPY --from=builder ... .prisma. This Client keeps the old T1 timestamp.
    • The Trap: You copy your schema.prisma file from your local computer: COPY ./prisma /app/prisma. This new file gets a timestamp of T2 (the time the Docker layer is built).

Result: When you run pnpm prisma migrate deploy, Prisma sees that T2 (schema) is newer than T1 (Client). It thinks the Client is outdated and runs generate, which causes the binary to be downloaded again.

ðŸ’Ą Three Ways to Fix This

The best solutions prevent Prisma from making this "new vs. old" comparison.

Solution 1 (The Best Way): Do Not Copy the Source Schema

The prisma migrate deploy command does not need the schema.prisma file itself. It only needs the migration files inside the migrations folder.

Change the runner stage:

FROM base AS runner
WORKDIR /app

# Copy the built Prisma Client (needed for your application or seeders)
COPY --from=builder /app/node_modules/.prisma /app/node_modules/.prisma

# ✅ CORRECT: Only copy the migration files
COPY ./prisma/migrations /app/prisma/migrations

# ❌ REMOVE THIS LINE: This is the problem file!
# COPY ./prisma /app/prisma 
Enter fullscreen mode Exit fullscreen mode

Why it works: Prisma cannot check the timestamp if the schema.prisma file is not in the final image.

Solution 2: Copy the Full node_modules from the Builder

If your builder stage successfully generated the client, copying the entire node_modules folder (which includes the client) from that stage might help ensure that all files within that folder have consistent timestamps from T1.

Change the runner stage:

FROM base AS runner
WORKDIR /app

# ✅ Copy the whole node_modules, which now includes the generated client from T1.
COPY --from=builder /app/node_modules /app/node_modules

# You still need to use Solution 1 and avoid copying the schema file!
COPY ./prisma/migrations /app/prisma/migrations
# ...
Enter fullscreen mode Exit fullscreen mode

Solution 3 (Quick Fix): Tell Prisma to Skip the Check

You can use an Environment Variable to make Prisma ignore the time check and assume the binary is already there.

Add this line to your runner stage:

FROM base AS runner
WORKDIR /app

ENV PRISMA_SKIP_BINARY_CHECK=1

# ... other COPY commands ...
Enter fullscreen mode Exit fullscreen mode

Note: This is fast, but if your builder stage ever fails to download the binary, this fix will hide the real error until the program starts.

Top comments (0)