DEV Community

Cover image for How did I shrink my NextJS Docker image by 90%?
João Santos
João Santos

Posted on

How did I shrink my NextJS Docker image by 90%?

Hey Folks!

Recently my team were working at a legacy NextJS project (next v10, without swc build, etc). In our infrastructure, we use AWS ECR and Kubernetes, so we build Docker Images of our applications.

But... something wasn't right.

Look at this image.

Docker image size: 1.37gb

This project were building a docker image with 1.37gb size!!

Our CircleCI production workflow (deploy) were lasting at least 8 minutes !!

Production pipeline 8 minutes

How did i resolve this issue?

First i must IDENTIFY why this were happening.

Once the problem was identified...

Why my docker image was getting bigger than 1gb?

R: Because we were copying all project files to docker. On DockerFile, we were using COPY . ., it's the same than say: Docker, you must copy all of the project to docker imag, okay? And "Docker" says: Yes, sir.

My old DockerFile.

This project, didn't had .dockerignore file too :(

FROM node:14-alpine

WORKDIR /usr/src/app

COPY / .

EXPOSE 3000
CMD [ "yarn", "start" ]
Enter fullscreen mode Exit fullscreen mode

How did i resolve this problem?

I started to investigate about some solutions for this BIG PROBLEM!!

I will describe my mindset flow to solution this problem.

  1. Update NextJS for latest version
    Like i said before, this project were using nextjs 10! I updated for nextjs 12.

  2. Find some solutions on stackoverflow/github issues
    We must do it for every problem that u doesn't know how to solution immediately.

  3. Find solutions on Nextjs docs/github.
    Here we go...

Nextjs Output Standalone

Since Next 12 we have output standalone option in Next.JS, what's it?

From NextJS website

Next.js can automatically create a standalone folder which copies only the necessary files for a production deployment including select files in node_modules.

To leverage this automatic copying you can enable it in your next.config.js:

module.exports = {
  output: 'standalone'
}
Enter fullscreen mode Exit fullscreen mode

This will create a folder at .next/standalone which can then be deployed on it's own without installing node_modules.

Hands On

  1. Added .dockerignore file
    I added that folders that isn't necessary to the project run. (.github folder, storybook, mocks, models, jest, etc, ...)

  2. Modified NextJS config
    I added the output: 'standalone' to next.config.js file, now, next would build in standalone mode, it would create a folder with only necessary files to the project run.

  3. Modified DockerFile
    Before my DockerFile were copying the entire project to the docker image, i changed it and now we're copying only the necessary files to our image, look below.

FROM node:14-alpine

WORKDIR /usr/src/app

// copying the `.next/standalone`, where's the necessary files for the production environment
COPY .next/standalone .

// copying static files, like (images, javascript chunks, etc)

COPY .next/static ./.next/static

// copying public assets (images, fonts, etc)
COPY public ./public

ENV NODE_ENV production
EXPOSE 3000

CMD [ "node", "server.js" ]
Enter fullscreen mode Exit fullscreen mode

Result

Before these changes, our docker image size were close to 1.3gb, now...

Build size now it's 100mb

Before these changs, our deploy pipeline were lasting 8 to 10minutes, now...

Production pipeline now it's 2minutes


My github: https://github.com/joaovsa7
LinkedIn: https://linkedin.com/in/jvsa7

Top comments (3)

Collapse
 
lirantal profile image
Liran Tal

Hi friend! If you're dockerizing Node.js apps to production you probably want to give this article a skim, as I'm seeing a bunch of stuff with your Dockerfile that could be improved: base image, not using an init system, not using a lower privileged user on the container, etc.

Collapse
 
jvsa7_ profile image
João Santos

Great tips! Thank you my friend

Collapse
 
stunaz profile image
stunaz

You were copying your entire node_modules directory before