open source developer



Weekend experiment: a node.js SPA with multi stage builds from docker

April 29, 2017
2 min read

Let's build a small node.js single page application (SPA) using the multi stage builds feature from docker to optimize the image size


With multi stage builds (a feature announced in the docker con last week) we can create a tiny image that get's pulled and pushed faster to the docker repository.

A Single Page Applications (SPA's) is a convenient use case to test the power of multi stage build easily in the node.js world.

Let's start with this.

First step: install docker 17.05-ce

Easy, go to https://www.docker.com/community-edition#/download Choose your platform AND, because we need multi stage builds and its still on the edge channel we need to choose that instead of the stable channel. Download, install.

Second step: Building a SPA

A single page application is just a static web page that can be served through any traditional web server.

For this example, let's pick a boilerplate SPA like create-react-app.

npm install -g create-react-app
create-react-app my-app
cd my-app/
npm start # if you want to test it and check the browser for it

Third step: create a Dockerfile

All right now the important thing, let's take a look at a candidate Dockerfile

# buildtime
FROM node AS nodebase
LABEL maintainer "nicosommi@gmail.com"
ADD . /usr/src/app
WORKDIR /usr/src/app
RUN npm i && npm run build
# runtime
FROM nginx:alpine
COPY --from=nodebase /usr/src/app/build /usr/share/nginx/html

So let's see.

We start with a node:latest image, no problem with the image size because now we have multi stage builds.

The LABEL maintainer, that's recent too, no more MAINTAINER special instruction, now it's a label.

We add the current directory to the appropiate location and set the working directory to it.

Install, build... and that's all that we need to generate our artifacts in our build folder.

So after that, we take for the runtime the small nginx:alpine image and we just copy the build folder to the right place.


Fourth step: build and run!

So now, let's build the image docker build -t my-app .

And now let's look it's size docker images

All right! less than 16 MB! With the whole thing, linux, nginx and our app!

That's great. Just the node_modules folder size after installation is around 130 MB... so this is a BIG win.

Let's try it
docker run -d --rm -p 8000:80 --name my-app my-app

Open chrome in localhost:8000 and enjoy.


Multi stage builds are great, it let's you easily build whatever you want and then create a thin self-sufficient pack with exactly what you need to let the user run your application.

By making this clear distinction between different stages, docker let's you think in a more organized way about the Dockerfile.

With multi stage builds the LAST stage is the one that is used on your final image. Don't forget that. For example, the ONBUILD instruction on a previous stage wont have any effect because it will be overwritten with the last stage of the Dockerfile.

As a side note, it is important to say that this may be a trigger to massively use webpack or some kind of bundler for standalone node.js applications. The node_modules folder get's really big very quickly.

Copyright by nicosommi 🐱