AboutBlogContact
DevOpsSeptember 30, 2019 2 min read 19

Docker Multi-Stage Builds: Slimming Down Your Production Images (2019)

AunimedaAunimeda
📋 Table of Contents

Docker Multi-Stage Builds: Slimming Down Your Production Images

In 2019, we are finally getting serious about container optimization. For years, our Dockerfiles were bloated. To build a Node.js or Go application, we needed the full compiler, npm, and hundreds of dev-dependencies in our image. But we don't need those to run the app.

Before multi-stage builds, we used the "Builder Pattern"—two separate Dockerfiles and a shell script to copy artifacts between them. It was messy.

The Modern Way: Multi-Stage

Multi-stage builds allow you to use multiple FROM statements in a single Dockerfile. Each FROM instruction starts a new stage. You can selectively copy artifacts from one stage to another, leaving everything you don't want behind.

Example: A Modern Node.js App

# Stage 1: The Build Environment
FROM node:12-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm install

COPY . .
RUN npm run build
# At this point, the image contains tsc, node_modules, and source code.

# Stage 2: The Production Environment
FROM node:12-alpine

WORKDIR /app
ENV NODE_ENV=production

# Only copy the production dependencies
COPY package*.json ./
RUN npm install --only=production

# Copy the compiled files from the builder stage
COPY --from=builder /app/dist ./dist

EXPOSE 3000
CMD ["node", "dist/server.js"]

Why This is Better

  1. Size: The final image doesn't contain the builder layers. Our image size drops from 800MB to 150MB.
  2. Security: Your production image doesn't contain build tools (like gcc, make, or npm). This significantly reduces the attack surface.
  3. Efficiency: You can use a heavy image (like Ubuntu) for building and a tiny image (like Alpine) for running.

Using Specific Targets

You can even use the --target flag with docker build to stop at a specific stage, which is great for running tests in CI without building the final production image.

docker build --target builder -t myapp:test .

In 2019, if your CI/CD pipeline is still pushing images that include your node_modules and .git folder, it's time to refactor. Multi-stage builds are the professional standard.

Read Also

The Rise of Containerization: Why We are Moving Our Production to Dockeraunimeda
DevOps

The Rise of Containerization: Why We are Moving Our Production to Docker

The 'it works on my machine' era is over. In 2018, we are standardizing our development and production environments using Docker to solve the environment parity problem once and for all.

Docker 1.0+: Deep Dive into Overlay Networking and VXLAN (2014)aunimeda
DevOps

Docker 1.0+: Deep Dive into Overlay Networking and VXLAN (2014)

Moving beyond single-host containers. How Docker's multi-host networking uses VXLAN encapsulation to create a seamless L2 network across your cluster.

Dockerizing Your Legacy Rails App: No More 'Works on My Machine' (2013)aunimeda
DevOps

Dockerizing Your Legacy Rails App: No More 'Works on My Machine' (2013)

The Docker revolution is just beginning. In 2013, we're using it to containerize legacy Ruby on Rails apps and solve the dependency nightmare.

Need IT development for your business?

We build websites, mobile apps and AI solutions. Free consultation.

Get Consultation All articles