Docker has become a popular tool for modern web development, allowing developers to create and deploy applications consistently across different environments. Dockerizing your Next.js application can provide many benefits, such as consistency, portability, and scalability. In this blog post, we will explore how to dockerize a Next.js application and take advantage of Docker’s benefits.
Overview
Steps:
Step 1: Create a Dockerfile for Next js
The first step is to create a Dockerfile, which is a script that contains instructions for building a Docker image. Here’s an example Dockerfile for a Next.js application:
FROM node:18-alpine AS base FROM base AS deps RUN apk add --no-cache libc6-compat WORKDIR /app COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./ RUN yarn --frozen-lockfile FROM base AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . RUN npm run build FROM base AS runner WORKDIR /app ENV NODE_ENV production ENV NEXT_TELEMETRY_DISABLED 1 RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs COPY --from=builder /app/public ./public COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static USER nextjs EXPOSE 3000 ENV PORT 3000 CMD ["node", "server.js"]
Above is an example of multi-stage build Dockerfile. Here’s a breakdown of what each section of the Dockerfile does:
FROM node:18-alpine AS base
: This sets the base image for the Dockerfile to node:18-alpine
, which is the official Node.js 18 Alpine image.
FROM base AS deps
: This creates a new stage in the Dockerfile, using the base
image as the base image for this stage. In this stage, we install any dependencies required for the Next.js application. We first install libc6-compat
package, which provides compatibility for programs that use glibc. Then we set the working directory to /app
and copy over the package.json
, yarn.lock
, package-lock.json
, and pnpm-lock.yaml
files. Finally, we install the dependencies using yarn
.
FROM base AS builder
: This creates another stage in the Dockerfile, using the base
image as the base image for this stage. In this stage, we copy over the files from the previous stage, including the installed dependencies. We then run the npm run build
command to build the Next.js application.
FROM base AS runner
: This creates the final stage in the Dockerfile, using the base
image as the base image for this stage. In this stage, we set the working directory to /app
, set the NODE_ENV
environment variable to production
, and disable Next.js telemetry. We then create a nodejs
group with a GID of 1001
and a nextjs
user with a UID of 1001
. We copy over the built Next.js application files from the builder
stage, set the user to nextjs
, expose port 3000
, set the PORT
environment variable to 3000
, and specify the command to run the Next.js server.
Why use multi-stage Dockerfile?
Multi-stage builds in Docker are used to optimize the size of the resulting image and reduce the attack surface. When building a Docker image, each layer added to the image adds size, which can slow down development and deployment processes. Multi-stage builds help to solve this problem by allowing for the creation of multiple stages in the Dockerfile, each of which can have a different base image and set of instructions. Each stage creates a separate layer in the resulting image, but you can choose which layers to keep and which to discard. This approach helps to minimize the size of the resulting image and reduce the attack surface by including only what is necessary to run the application in production. Overall, multi-stage builds are an important tool for optimizing Docker images and making them more efficient and secure.
Step 2: Build the Docker Image
Once you’ve created the Dockerfile, you can build the Docker image using the docker build
command. Here’s an example command:
docker build -t my-next-app .
In this command, we’re using the -t
flag to specify the name of the Docker image (my-next-app
), and the .
at the end specifies the location of the Dockerfile (in the current directory).
To check docker images, run below command:
docker images
Step 3: Run the Docker Container
After building the Docker image, you can run the Docker container using the docker run
command. Here’s an example command:
docker run -p 3000:3000 -d my-next-app
In this command, we’re using the -p
flag to map the container’s port 3000 to the host machine’s port 3000, -d
is to run the container in background, and my-next-app
specifies the name of the Docker image we want to run.
To check running containers, run the below command:
docker ps
To check logs, run the below command:
docker logs -f 5156a31ad3a5 #replca with your container id/name
In this command, we’re using -f to get the running logs, and “5156a31ad3a5” is a container id you can also use container name instead of id.
To access your application, open your browser and go to http://localhost:3000