I spent too long dealing with massive final images because I was too lazy to think about what actually needed to ship. Switched to multi-stage builds about two years ago and never looked back.
Here's what I'm running now for a typical Lambda function:
FROM node:20-alpine as builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package.json .
RUN npm prune --production
CMD ["node", "dist/index.js"]
Final image is 180MB instead of the 650MB monster I had before. Cold starts dropped. Cost went down. Simple win.
The build stage keeps dev dependencies (typescript, esbuild, whatever), then the final stage only gets what actually runs. No extra junk. No tar balls of dev tooling.
Used to think it was overcomplicated. It's not. Just separate your concerns into stages and only copy what you need forward. If you're still shipping your node_modules with prettier in production, you're wasting money on your cloud bill.
No responses yet.