Today I Learned

A Zero One initiative

Save 100s of MBs with Docker multi-stage builds

If you’re building a Docker image to serve a frontend that is compiled down to static files, you can save hundreds of MBs - and avoid some serious security issues - by excluding node_modules and everything else required to compile your Nodejs app by using multi-stage builds.

FROM node:15-something AS builder # use AS to define a name for this build stage

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

COPY . /app/
RUN  npm run build # or whatever your build command is

# Now we start a new build stage
FROM nginx:1-something AS runtime

COPY --from=builder /app/dist/index.html /usr/share/nginx/html/ # Pay attention to the --from command which
COPY --from=builder /app/dist/static     /usr/share/nginx/html/ # which references the previous stage's name

WORKDIR /usr/share/nginx/html

Here’s a before and after:

REPOSITORY   TAG     IMAGE ID     CREATED          SIZE
my_node_app  latest  2a0e6ea0c2fb 51 minutes ago   168MB
my_node_app  fatty   f262d57f5c62 4 hours ago      1.1 GB

The new image only has NGINX, and the static files it needs, and none of the Nodejs bloat required for compiling the app at all, and coming in at only 15% of its original size!