From 155e7849e18e47aaa37f4057a3cfc1d70ae7b625 Mon Sep 17 00:00:00 2001 From: jason Date: Sun, 29 Mar 2026 22:12:38 -0500 Subject: [PATCH] Fix runtime stage: install prod deps instead of copying node_modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pnpm uses a symlink-based virtual store (.pnpm/) that breaks when copied between Docker stages — Node can't resolve modules from the copied tree, causing 'Cannot find module express' at startup. Replace the broken COPY with a proper pnpm install --prod in the runtime stage. Layer caching still applies: manifests + lockfile are copied before source so the install layer is only rebuilt when deps change. Co-Authored-By: Claude Sonnet 4.6 --- Dockerfile | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index d96207b..5c3c3e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -51,11 +51,18 @@ FROM node:22-alpine AS runtime # Install tini for proper PID 1 signal handling RUN apk add --no-cache tini su-exec +RUN corepack enable && corepack prepare pnpm@latest --activate + WORKDIR /app -# No native deps — runtime only needs node_modules for pure-JS packages (express, cors, etc.) -# pnpm hoists everything to the root node_modules (shamefully-hoist=true in .npmrc) -COPY --from=server-builder /build/node_modules ./node_modules +# Copy workspace manifests and lockfile — pnpm needs these to install correctly +COPY pnpm-workspace.yaml package.json pnpm-lock.yaml* .npmrc ./ +COPY apps/server/package.json ./apps/server/ +COPY apps/client/package.json ./apps/client/ + +# Install production dependencies only — fresh install avoids broken symlinks +# from COPY-ing pnpm's virtual store between stages +RUN pnpm install --prod --frozen-lockfile # Copy compiled server output (includes dist/db/migrations/*.js compiled by tsc) COPY --from=server-builder /build/apps/server/dist ./apps/server/dist