Ship only production dependencies in the api and preview-edge images - #214
Merged
Merged
Conversation
`pnpm install --prod` over an existing tree only unlinks devDependencies from the top level of node_modules; the packages themselves stay in node_modules/.pnpm and were copied into the runtime image. - api/Dockerfile, preview-edge/Dockerfile: remove node_modules before the --prod install, and add --offline so it relinks from the builder's store instead of re-downloading. Measured with the committed lockfiles: api 219 MB / 362 packages -> 109 MB / 180; preview-edge 74 MB / 176 -> 13 MB / 89. - api-ci.yaml: correct a comment that listed scripts/ among the Dockerfile's inputs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| 🟣 Preview removed (PR closed). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Both Dockerfiles ran a full
pnpm install, built, then ranpnpm install --frozen-lockfile --prodin the same directory and copiednode_modulesinto the runtime stage. That second install removes the devDependencies' top-level links but leaves the packages themselves innode_modules/.pnpm, so typescript, eslint, vitest, knip, esbuild, kysely-codegen and their dependencies were all in the production images. The app couldn't import them, but they cost image size and pull time, and they add to what vulnerability scanners flag.The fix:
rm -rf node_modulesbefore the prod install, plus--offlineso the install relinks from the store the first install filled (and fails loudly rather than re-downloading if that store is ever missing).Measured with the committed lockfiles and pnpm 11.21.0 (on macOS, so platform binaries differ slightly from the image):
--prodinstall)node_modulesnode_modulesargon2andsharpstill load from the pruned api tree.tsxstays: it's a real dependency, becauseapi/k8s/migrate-job.yamlruns the migrations through it from the image.Also corrects an
api-ci.yamlcomment that listedscripts/among the Dockerfile's inputs.Deploy notes
No web change, so the two-commit rule doesn't apply. Merging redeploys the API (
api/Dockerfile) and preview-edge.api-ci.yaml'simagesjob builds both images on this PR, which checks the Docker build itself.🤖 Generated with Claude Code