Production Dockerfile for Next.js (React) project

Do you want to dockerize your Next.js project? Here is a multi-stage Dockerfile that reduced my docker image size a lot.

cover image

Initial Dockerfile

This is Dockerfile that I initially used for my project. This is the simplest Dockerfile that will build a docker image and start it on port 3000.

FROM mhart/alpine-node WORKDIR /app COPY . . RUN yarn install RUN yarn build EXPOSE 3000 CMD ["yarn", "start"]

It works as it should, but the thing is that image it builds takes nearly 1 GB of memory (this size depends on the project). That size was too big for me, so I decided to try, and reduce it as much as I could.

Updated Dockerfile

After some research, I created a new Dockerfile that reduced image size, to about 300 MB. The difference was pretty noticeable, especially when pushing that image to the server.

This project is using Next.js version 9.5.

Here is my updated version of Dockerfile for Next.js.

FROM node:alpine as BUILD_IMAGE WORKDIR /app COPY package.json yarn.lock ./ # install dependencies RUN yarn install --frozen-lockfile COPY . . # build RUN yarn build # remove dev dependencies RUN npm prune --production FROM node:alpine WORKDIR /app # copy from build image COPY --from=BUILD_IMAGE /app/package.json ./package.json COPY --from=BUILD_IMAGE /app/node_modules ./node_modules COPY --from=BUILD_IMAGE /app/.next ./.next COPY --from=BUILD_IMAGE /app/public ./public EXPOSE 3000 CMD ["yarn", "start"]

Brief explanation

If you are using Docker then this file will look familiar and easy to read, but here is a brief explanation.

First, I am using alpine image. This one's preferred for the smaller image size, if you don't need a specific Linux distro.

The thing that made the biggest difference is the multi-stage build. It first creates a build image and installs all dependencies. In the next stage, it will copy them to the runtime image, and it will also get rid of the yarn cache directory.

I also added the RUN npm prune --production command. This means that all packages specified in devDependencies will be removed, since we don't need them in production.

I am sure there are more ways to reduce the image size, and I will update this post when I implement them.