Production Dockerfile for Next.js (React) project
You can read more stories at miletadulovic.me
Do you want to dockerize your Next.js project? Here is a multi-stage Dockerfile that reduced my docker image size a lot.
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-nodeWORKDIR /app
COPY . .RUN yarn install
RUN yarn buildEXPOSE 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_IMAGEWORKDIR /appCOPY package.json yarn.lock ./# install dependencies
RUN yarn install --frozen-lockfileCOPY . .# build
RUN yarn build# remove dev dependencies
RUN npm prune --productionFROM node:alpineWORKDIR /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 ./publicEXPOSE 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.