Skip to content

Latest commit

Β 

History

History

nextjs

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Optimize Dockerfile images for NextJS

Background

NextJS Docker images is too big. So, this article will focus on the way optimize dockerfile for production. Here, i will use 2 ways for optimize docker images.

Setup

First, we need to create a project with nextjs. Quickly, i use an example of Vercel, project in here.

Project structure:

.
β”œβ”€β”€ @types
β”‚   └── remark-html.d.ts
β”œβ”€β”€ README.md
β”œβ”€β”€ _posts
β”‚   β”œβ”€β”€ dynamic-routing.md
β”‚   β”œβ”€β”€ hello-world.md
β”‚   └── preview.md
β”œβ”€β”€ components
β”‚   β”œβ”€β”€ alert.tsx
β”‚   β”œβ”€β”€ avatar.tsx
β”‚   β”œβ”€β”€ container.tsx
β”‚   β”œβ”€β”€ cover-image.tsx
β”‚   β”œβ”€β”€ date-formatter.tsx
β”‚   β”œβ”€β”€ footer.tsx
β”‚   β”œβ”€β”€ header.tsx
β”‚   β”œβ”€β”€ hero-post.tsx
β”‚   β”œβ”€β”€ intro.tsx
β”‚   β”œβ”€β”€ layout.tsx
β”‚   β”œβ”€β”€ markdown-styles.module.css
β”‚   β”œβ”€β”€ meta.tsx
β”‚   β”œβ”€β”€ more-stories.tsx
β”‚   β”œβ”€β”€ post-body.tsx
β”‚   β”œβ”€β”€ post-header.tsx
β”‚   β”œβ”€β”€ post-preview.tsx
β”‚   β”œβ”€β”€ post-title.tsx
β”‚   └── section-separator.tsx
β”œβ”€β”€ interfaces
β”‚   β”œβ”€β”€ author.ts
β”‚   └── post.ts
β”œβ”€β”€ lib
β”‚   β”œβ”€β”€ api.ts
β”‚   β”œβ”€β”€ constants.ts
β”‚   └── markdownToHtml.ts
β”œβ”€β”€ next-env.d.ts
β”œβ”€β”€ package.json
β”œβ”€β”€ pages
β”‚   β”œβ”€β”€ _app.tsx
β”‚   β”œβ”€β”€ _document.tsx
β”‚   β”œβ”€β”€ index.tsx
β”‚   └── posts
β”‚       └── [slug].tsx
β”œβ”€β”€ postcss.config.js
β”œβ”€β”€ public
β”‚   β”œβ”€β”€ assets
β”‚   β”‚   └── blog
β”‚   β”‚       β”œβ”€β”€ authors
β”‚   β”‚       β”‚   β”œβ”€β”€ jj.jpeg
β”‚   β”‚       β”‚   β”œβ”€β”€ joe.jpeg
β”‚   β”‚       β”‚   └── tim.jpeg
β”‚   β”‚       β”œβ”€β”€ dynamic-routing
β”‚   β”‚       β”‚   └── cover.jpg
β”‚   β”‚       β”œβ”€β”€ hello-world
β”‚   β”‚       β”‚   └── cover.jpg
β”‚   β”‚       └── preview
β”‚   β”‚           └── cover.jpg
β”‚   └── favicon
β”‚       β”œβ”€β”€ android-chrome-192x192.png
β”‚       β”œβ”€β”€ android-chrome-512x512.png
β”‚       β”œβ”€β”€ apple-touch-icon.png
β”‚       β”œβ”€β”€ browserconfig.xml
β”‚       β”œβ”€β”€ favicon-16x16.png
β”‚       β”œβ”€β”€ favicon-32x32.png
β”‚       β”œβ”€β”€ favicon.ico
β”‚       β”œβ”€β”€ mstile-150x150.png
β”‚       β”œβ”€β”€ safari-pinned-tab.svg
β”‚       └── site.webmanifest
β”œβ”€β”€ styles
β”‚   └── index.css
β”œβ”€β”€ next.config.js
β”œβ”€β”€ tailwind.config.js
└── tsconfig.json

Then, install and build this blog:

➜  blog-starter git:(master) βœ— yarn
➜  blog-starter git:(master) βœ— yarn build
➜  blog-starter git:(master) βœ— yarn start

Your blog should be up and running on localhost:3000.

Build on Docker

Ignore unneeded files with .dockerignore:

node_modules
*.DS_Store
.next
.gitignore
README.md
.dockerignore
LICENSE
.docker
.gitlab
.git

We have 3 scenarios dockerfile in here. First, i'll use Basic Dockerfile:

➜  blog-starter git:(master) βœ— docker build -t blog-with-basic-dockerfile -f .docker/basic.dockerfile .

basic

# Check docker images
➜  blog-starter git:(master) βœ— docker images
REPOSITORY                                       TAG                               IMAGE ID       CREATED          SIZE
blog-with-basic-dockerfile                       latest                            b70f75178890   8 seconds ago    370MB

In this scenarios, we built nextjs image with size 370MB.

Next, we use multi-stage docker with Multi Stage Docker:

➜  blog-starter git:(master) βœ— docker build -t blog-with-multistage-dockerfile -f .docker/multistage.dockerfile .

multi

# Check docker images
➜  blog-starter git:(master) βœ— docker images
REPOSITORY                                           TAG                               IMAGE ID       CREATED           SIZE
blog-with-multistage-dockerfile                      latest                            07c84ea2173a   38 seconds ago    339MB

In this way, i use module node-prune in stage BUILD after install packages. node-prune can remove unnecessary files from node_modules:

         files total 43,924
       files removed 12,814
        size removed 28 MB
            duration 866ms

Hehe, reduced 28MB. You can follow this guide for setup in your base node image. So, this images has been optimized 370MB -> 339MB.

Finally, we build dockerfile with multi-stage docker and enable mode standalone of NextJS. Create file next.config.js with content:

module.exports = {
    output: "standalone"
}

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

Let's start with Dockerfile:

➜  blog-starter git:(master) βœ— docker build -t blog-with-multistage-standalone-dockerfile -f .docker/multistage_standalone.dockerfile .

standalone

# Check docker images
➜  blog-starter git:(master) βœ— docker images
REPOSITORY                                                      TAG                     IMAGE ID       CREATED           SIZE
blog-with-multistage-standalone-dockerfile                      latest                  07c84ea2173a   38 seconds ago    119MB

WoW! Great ... The size of images is only 119MB.

3 images

So, I have presented 3 ways to optimize image size but ... it build very slow. In the next post, i will show you how to build image faster.

Thanks for reading 😁😁😁