How to dockerize a nextjs app?

How to dockerize a nextjs app?

Nextjs is a widely used react framework for building a full stack app. In this post we will see how do we dockerize a nextjs application.

Introduction

While this post is about dockerizing a nextjs application it is important for us to know the basics like what is docker and containers.

Whenever we are building an application there are lots of dependencies that are needed to have the application up and running. Let us say we are building a fullstack nextjs application in our local system, this would need us to install dependencies in our local machine like nodejs, mongodb, react, nextjs etc... We will have to first install nodejs in our system which comes as a different package altogether and has to be installed on our local machine separately. Similarly we will have to install mongodb as a separate software in our machine so that our nextjs app can access the database locally.

Now consider that you have been working on the application and a few months later a new team member joins your who has to work on your app. He will have to do all those software installation again on their system and it is possible that the version of software that they install on their machine is different than what you had installed on your machine earlier. This might lead to compatibility issues and to resolve this either you have to update your app or you will have to install the same version of software which you had installed to be installed on the machine of new member. This is a cumbersome task.

We used you land up in such type of issues when dockers and containers did not exist. Well it is not just about the development machine. The software dependencies has to be installed on servers as well where you deploy your app. So high probablity of landing up into issues over there as well.

This has been a common problem where the developers says its working on his machine but not working on server. We then end up figuring out the issue and ultimately find the issue to be related to the version of software installed on the particular environment.

Well thanks to the concept of container based application. This problem is effectively handled if we use a containerized application. Also there are numerous other benefits of a containerized application.

What are containers ?

A container is a lightweight, standalone, executable package that includes everything needed to run a piece of software, including the code, runtime, system tools, libraries, and settings. Containers provide process and resource isolation at the operating system level, allowing applications to run in isolated environments without interfering with each other. Containers are portable, efficient, consistent, and flexible, making them ideal for packaging and deploying applications across different environments.

What is docker ?

Docker is a platform and a tool that simplifies the process of creating, deploying, and managing containers. Docker introduced the concept of containerization to a broader audience by providing an easy-to-use interface for building, running, and distributing containers. Docker also includes features such as Dockerfile (for defining container configurations), Docker images (for packaging applications and dependencies), and Docker Hub (for sharing and distributing Docker images).

Well docker and containers are separate topic altogether. Let us now see how do we dockerize our nextjs app.

Creating a new nextjs app

The prerequisite to create a nextjs app is nodejs. If you have the nodejs version 18 or higher installed on your system you can create and run a new nextjs app by the following commands.

npx create-next-app@latest my-app
cd my-app
npm run dev

You can now navigate to http://localhost:3000 to see your app running.

Creating a docker file.

Assuming that you have already installed docker on your machine we will not create a docker file in the root of you application. A Dockerfile is a text document that contains instructions for building a Docker image. It serves as a blueprint for creating a containerized environment for your application. The primary use of a Dockerfile is to define the environment inside the Docker container, including the base image, dependencies to install, environment variables, and other settings.

Create a new file with the name Dockerfile without any extension and add the below mentioned contents in the file.

FROM node:20
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]

Lets understand what each line is doing in the above code -

FROM node:20: This line specifies the base image for your Docker container. In this case, it's using the official Node.js Docker image with version 20. This means that your container will be based on the Node.js runtime environment version 20, providing the necessary tools and dependencies to run Node.js applications.

WORKDIR /app: This line sets the working directory inside the container to /app. This is where all subsequent commands in the Dockerfile will be executed. It's a best practice to set a specific working directory to organize files and ensure consistency.

COPY package*.json ./: This line copies the package.json and package-lock.json files from the host machine to the /app directory inside the container. This step is done before running npm ci to leverage Docker's layer caching mechanism. It ensures that dependencies are only installed when the package.json files have changed.

RUN npm ci: This line runs the npm ci command inside the container. npm ci is similar to npm install, but it's optimized for continuous integration (CI) environments, ensuring deterministic and reproducible installs based on the package-lock.json file.

COPY . .: This line copies the rest of the application files from the host machine to the current working directory (/app) inside the container. This includes the application source code, configuration files, and any other necessary files.

RUN npm run build: This line executes the npm run build command inside the container. This command is typically used for building or compiling the application. For example, if you're using a frontend framework like React, Vue.js, or Angular, this command might compile JSX/TSX files into JavaScript or bundle assets.

EXPOSE 3000: This line exposes port 3000 on the container to allow communication with services outside the container. However, this is just a declaration and does not actually publish the port to the host machine. You would still need to publish the port when running the container.

CMD ["npm", "start"]: This line specifies the default command to run when the container starts. In this case, it's running npm start, which typically starts the application. This command will be overridden if a different command is provided when running the container.

Build the Docker image

With the above docker file in place we can now build the docker image using the docker file by running the command with the syntax below.

docker build -t <image_name>:<tag> .

Replace <image_name> with the desired name for your Docker image and with a version or tag (e.g., latest). The . at the end specifies the build context, which includes the current directory containing the Dockerfile and any files it references.

For example, if you want to name your image my-node-app with the latest tag, you would run:

docker build -t my-app:latest .

Run the docker image

To run the Docker image that you've built, you can use the docker run command. You can run the Docker image you created with the Dockerfile provided:

docker run -p 3000:3000 my-app:latest

docker run: This command is used to run a Docker container based on a specific image. -p 3000:3000: This option maps port 3000 on your local machine to port 3000 inside the container. This allows you to access your application running inside the container via port 3000 on your localhost. my-app:latest: This specifies the name and tag of the Docker image you want to run. Replace my-app with the name you gave to your Docker image, and latest with the tag you used.

When you run this command, Docker will create a new container based on your image and start it. The container will execute the default command specified in your Dockerfile, which in this case is npm start, starting your Node.js application.

If your Node.js application is running correctly, you should be able to access it by opening a web browser and navigating to http://localhost:3000

Conclusion

In this post covered the following points -

  • Understanding the need of containerized application
  • What are containers ?
  • What is docker ?
  • Creating a Dockerfile
  • Build a docker image
  • Run a docker image

Please share the post by clicking the social media icons at the beginning of the post.

Thank you for reading and see you in the next post !👋

Buy a coffee for sudshekhar