Introduction
First thing first, I expect you to know what is Docker, but if you don’t:
Docker is an open platform for developing, shipping, and running applications
You can spend time learning about it
NextJS, in other hand, is a flexible React framework that gives you building blocks to create fast web applications.
NextJS, in other hand, is a flexible React framework that gives you building blocks to create fast web applications.
Dockerize your App
Before we optimize anything, we have to dockerize the application first. Let’s say our application name is my-space
. Starting with:
Create the Dockerfile
:
touch Dockerfile
Ignore unnecessary files in dockerignore
:
node_modules
.next
.vscode
.gitignore
README.md
.dockerignore
.git
Dockerize it:
This is the most basic example on how to dockerize your app, now let’s build it with:
docker build -t my-space .
Now look at the size:
*That’s just crazy, 2.42gb!!
*
Unbelievable right, we can’t publish this image, it’s just too heavy !
Reduce the image size
Use alpine
The Node.js Docker team maintains a node:alpine
image tag and variants of it to match specific versions of the Alpine Linux distributions with those of the Node.js runtime. The original version size is about 1gb.
Now we will move to the alpine version:
Now the size shrank to 1.65gb, 800mb smaller. That’s a good start !
Multi-stages builds
Multi-stage builds are useful to anyone who has struggled to optimize Dockerfiles while keeping them easy to read and maintain.
We will create 2 stages in the Dockerfile
. I will call it builder
and runner
In this way we can get rid of unnecessary files in our image:
We will pick files from the builder
and move it to the runner
that we will eventually use:
*The size comes down to 1.36gb, about 300mb smaller, we are doing good !
*
Remove duplicate layers
You can see something is duplicating. Yes, we install the dependencies twice for each stage. Although this works and the project size is still the same. The image size is still big because of caching and layers.
So we can pick the node_modules
from the build stage:
The size now is quite decent for a NextJS app, below 500mb
But we can still make it lighter !
Output File Tracing
During a build, Next.js
will automatically trace each page and its dependencies to determine all of the files that are needed for deploying a production version of your application.
This feature helps reduce the size of deployments drastically. Previously, when deploying with Docker you would need to have all files from your package’s dependencies installed to run next start
. Starting with Next.js 12, you can leverage Output File Tracing in the .next/
directory to only include the necessary files.
In your next.config.js
file, enable the standalone output
experimental: {
outputStandalone: true,
},
This will create a folder at .next/standalone
which can then be deployed on its own without installing node_modules
.
*The size is now 176mb! Small enough for most cases
*
Conclusion
This is just a simple example on how to optimize your docker image sizes, you can look deeper in Docker docs to find the most suitable treatment for your app!
Top comments (5)
Thank you Duc Le for the great tutorial!
Here's updated code in a dockerfile.
next.config.js
.dockerignore
dockerfile
Love this! Did a similar change to reduce an app (older version of next) from ~1.25gb to ~325mb.
I added
RUN yarn --frozen-lockfile --production
After yarn build to reduce the size of node modules and exclude dev dependencies from the final image.
Awesome article, thanks
Can you plese share a gist so that we can copy the code from?
Thanks
Great article.
Regarding your question, can I apply the same concept to an API project? Another question: what software are you using to analyze the size of the Docker image?
I use Docker itself