Docker images can get very large if you use an official Node image to run on your server. But you don't need most of the features it offers to build a small project. I will show how to reduce the size of an image from 1.36 GB to 140 MB using a multi-stage build. First, let's build a starter image of my Node.js project:
FROM node:16
WORKDIR /project
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
CMD node build/index.js
There are quite a few problems with this:
- We included node_modules and git folders in our build.
- We used all dev dependencies that are redundant in production.
Let's solve these issues. Add the .gitignore file:
.git
build
node_modules
And remove development dependencies after the build command:
RUN npm prune --omit=dev
Shaving off 100 MB as a result of such a simple operation is pretty good, but we can do much more with a multi-stage build and node-alpine image. The first step is to tag our initial build as "initial":
FROM node:16 as initial
Now, we add a new stage with node-alpine image and copy compiled build files and node_modules from the initial build:
FROM node:16-alpine
WORKDIR /project
COPY --from=initial /project/node_modules /project/node_modules
COPY --from=initial /project/build /project
The final version of the Dockerfile will look like this:
# stage 1
FROM node:16 as initial
WORKDIR /project
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
RUN npm prune --omit=dev
# stage 2
FROM node:16-alpine
WORKDIR /project
COPY --from=initial /project/node_modules /project/node_modules
COPY --from=initial /project/build /project
CMD node index.js
Now, let's see the result of this build:
This final image works just as well as the first one, and we shaved off ~1.2 GB.