Dockerizing your Next.js/React Application!
Tags: react, nextjs, docker, codenewbie
Published: 2022-03-28 17:01:57

## What is Docker?

Docker is a software framework for building, running, and managing containers on servers and the cloud. Think of Docker as a CLI but for the cloud.

For this tutorial, we will be using `Next.js` sample application and create a `Dockerfile` in order to Dockerize it.

## Requirements:

In order to complete Dockerizing your `Next.js` app, you will need the following:

- `Docker` installed on your computer.
- `Node.js` and `npm/yarn` installed on your system in order to create Next app.

## Creating a sample `Next.js` app

If you already have an application that you want to dockerize then, you can proceed with further steps else let’s create a `next.js` app.

Run the following command on your terminal:

```
yarn create next-app 
```



This command will initialize files and configurations that are required to create and run your `next.js` application.

## Creating a `Dockerfile`

First, let’s open our app in VS Code or any Code Editor of your choice.

Run the following commands:

```
cd <your app name>
```

```
code . 
```
(assuming you have vscode configured)

Here, you will see the directories of your application. That would look something similar like this.

[ Note: I am using TypeScript that’s why you are seeing `tsconfig.json` and files that ends with `.ts` ]


![file contents](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pt1050neh8694gdzl9on.png)

Go ahead and create a new file and name it `Dockerfile`. By default, this file is recognized by `docker` and it will executes bunch of commands and instructions that we will provide.

Remember: The commands will be executed in order of how they are written.

Inside the `Dockerfile` write these codes. I will go through each one and explain how it works at the end of the tutorial.

[Note: I am using `yarn` for this tutorial, you can use `npm` but you will have to swap those `yarn` executable code with `npm`] 

```docker
FROM node:lts as dependencies
WORKDIR /<your-app-name>
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile

FROM node:lts as builder
WORKDIR /<your-app-name>
COPY . .
COPY --from=dependencies /<your-app-name>/node_modules ./node_modules
RUN yarn build

FROM node:lts as runner
WORKDIR /<your-app-name>
ENV NODE_ENV production

COPY --from=builder /<your-app-name>/public ./public
COPY --from=builder /<your-app-name>/package.json ./package.json
COPY --from=builder /<your-app-name>/.next ./.next
COPY --from=builder /<your-app-name>/node_modules ./node_modules

EXPOSE 3000
CMD ["yarn", "start"]
```

## Building Docker Image

Execute the following command to build the `Docker` image.

```
docker build . -t <project-name>
```

This command will build the `Docker` image with the name `<project-name>`.

Running the `Docker` image once the build is over with the following command.

```
docker run -p 3000:3000 <project-name>
```

Now, open the browser and navigate to 

```
http://localhost:3000 
```
to view your project.

## CONGRATULATIONS! You have successfully dockerized your application!


![Congrats](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/65c3jebnnj1f9aggp5wt.gif)

## Visiting contents of the `Dockerfile`

Now, let’s go through the code contents of the `Dockerfile`.

Remember, the code are executed based on how they are written, `top-down` approach.

Lets go through the code in three different stages in top-down approach:

1. Installing dependencies
2. Building our `Next.js` application
3. Configuring the runtime environment for our application

### 1. Installing Dependencies

```docker
FROM node:lts as dependencies
WORKDIR /<your-app-name>
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
```

Let’s talk about what is happening on this code.

First, we want to define what image we want to build from for which we are using the latest `node` version with `node:lts` 

You could use any specific version of node. For example: `FROM node:16` would build your image with Node version 16. We are using `as dependencies` so that we can export this code and reuse it later when building our application in `docker`. 

Second, we want to create an application directory which holds our application code with `WORKDIR`. 

Third, we want to copy our `package.json` and `yarn.lock` files which allows us to take advantage of cached Docker layers. A good explanation of Docker Caching is [here](https://medium.com/swlh/docker-caching-introduction-to-docker-layers-84f20c48060a).

Finally, we want to be able to run our `yarn install` to install these dependencies. We are using `--frozen-lockfile` because our `yarn.lock` or `package-lock.json` gets updated when running `yarn install` ( or `npm install`). We do not want to check for these changes.

If you are using `npm` you can use `npm ci` (ci means clean install / use it for production or else just use `RUN npm install`)

For `yarn` its `--frozen-lockfile`

### 2. Building our `Next.js` application

```docker
FROM node:lts as builder
WORKDIR /<your-app-name>
COPY --from=dependencies /<your-app-name>/node_modules ./node_modules
RUN yarn build
```

Let’s look at the build. 

Here, we build our application copying dependencies from node_modules.

If you are using `npm` then use `RUN npm build`.

```docker
FROM node:lts as runner
WORKDIR /<your-app-name>
ENV NODE_ENV production
```

After building our project, we want to be able to run it. 

### 3. Configuring the runtime environment for our application

```docker
COPY --from=builder /<your-app-name>/public ./public
COPY --from=builder /<your-app-name>/package.json ./package.json
COPY --from=builder /<your-app-name>/.next ./.next
COPY --from=builder /<your-app-name>/node_modules ./node_modules

EXPOSE 3000
CMD ["yarn", "start"]
```

Here, we want to be able to bundle the app source code inside our Docker image that’s why we are using `COPY`.

Finally, we want to define a command to run our app using `CMD` which defines the runtime.

For our runtime, we are using `yarn` command.

If you have `Docker` Application installed, you can view your container on the dashboard and run it from there which would look something like the images below.


![Docker Dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sgn0i3xa4v26bodc1lhq.png)

![Docker Dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m6pndsjc57mq4qfu7wqp.png)

<hr />
You did it!
Thanks for reading. If you have any questions, feel free to send them my way on Twitter <a href="https://twitter.com/developernit" target="blank">@developernit</a>