Creating a Docker Dev Container for a NextJS App

A practical DevOps example using Docker for testing a NextJS Web App


Docker2001

Introduction

This blog is built with Next.js. I'll share how I test changes in my blog before publishing them on Vercel. By using Docker, I can spin up a test environment anywhere without risking issues caused by platform differences.

The project doesn't have all the code under a /src folder, which makes some configuration look a bit messy. I'll definitely organize this differently in future projects.

This topic of this post may look similar to the name of the Devcontainers project, I have to make clear that this post is not using this project. I might look at the Devcontainers project further up the road, it has a lot of cool automation stuff built around containers for development.

Building the Docker Image

We'll start by dockerizing the development environment with a Dockerfile. To avoid unnecessary bloat, we'll use a Node Docker image running on an Alpine Linux distribution, which only takes up around 5MB of space.

dev.Dockerfile

FROM node:22-alpine
 
WORKDIR /app
 
# For caching optimization, copy files in stages. This stage builds the dev dependancies
COPY package*.json .
RUN npm ci
 
# Let's copy the rest of the code and config
COPY . .
 
#Execute the NextJS Dev Environment
CMD [ "npm", "run", "dev" ]

Docker Compose

The container will run the image from the Dockerfile with the following configuration:

docker-compose.dev.yaml

services:
  app:
    container_name: app
    build:
      context: .
      dockerfile: dev.Dockerfile
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: development
    # Volumes for the Dev Server to detect code changes
    volumes:
      - ./app:/app/app
      - ./lib:/app/lib
      - ./assets:/app/assets
      - ./content:/app/content
      - ./config:/app/config
      - ./public:/app/public
      - ./styles:/app/styles
      - ./components:/app/components

Files and folder to be ignored in the container

Some files and folders are not needed in the container. For example, ./node_modules will be generated by the following two lines from the dev.Dockerfile:

COPY package*.json .
RUN npm ci

.dockerignore

.git
*Dockerfile*
*docker-compose*
node_modules
README.md
.next
npm-debug.log

Running the container

The command below will spin up the Dev Container:

docker compose -f docker-compose.dev.yaml up

Summary

We have now containerized the development environment of a static web app. We don't really need custom file names like dev.Dockerfile and docker-compose.dev.yaml, but I chose to use them to prepare for creating a production container. My blog is currently running on Vercel, but if I decide to move to a VPS, I'll prepare a production container and share it in the future. I'll also create a staging environment if I make significant changes to the code, to ensure everything builds properly.