This blog was originally posted by the author here
Why Use Docker for Your Next.js App ?
By containerizing your app, you create a consistent, portable, and reproducible environment that runs the same way on any machine — from your laptop to a production server.
How to Dockerize a Next.js App: A Step-by-Step Guide
Are you ready to take your Next.js application from “works on my machine” to “works everywhere”? 🚀 Docker is the answer! As a Next.js developer, you’ve likely experienced the headaches of environment inconsistencies. Maybe a dependency is different, or someone on your team is on a different OS. By containerizing your app, you create a consistent, portable, and reproducible environment that runs the same way on any machine — from your laptop to a production server.
This guide will walk you through the entire process of creating an optimized Dockerfile for your Next.js application. We’ll cover everything from setting up the project to building and running your Docker image, making sure it’s production-ready.
Why Use Docker for Your Next.js App?
Why bother with Docker when Vercel exists? While Vercel is great for seamless deployments, there are many reasons to use Docker, especially in enterprise environments or for custom deployments.
- Portability & Consistency: A Docker container bundles your app and all its dependencies into a single package. This eliminates the “it works on my machine” problem, ensuring a consistent environment for development, testing, and production.
- Simplified Deployment: Once your app is in a container, deploying it to any cloud provider that supports Docker (like AWS, Google Cloud, or DigitalOcean) is straightforward. It standardizes your deployment process.
- Scalability: Docker makes it incredibly easy to scale your application. You can run multiple instances of your container to handle increased traffic, and container orchestration tools like Kubernetes can manage this for you.
- Isolation & Security: Containers provide an isolated environment, preventing your application’s dependencies from conflicting with other applications on the same host. This also adds a layer of security, as the app runs with minimal permissions.
Step 1: Configure Your Next.js App for Standalone Mode (Optional)
Before we write the Dockerfile, we need to tell Next.js to produce a special output that’s optimized for Docker. Next.js has a built-in standalone mode that creates a self-contained folder with only the necessary files for a production build, including a minimal Node.js server. This drastically reduces the final Docker image size.
But you can skip this step but it will just reduce the size of the docker image.
In your next.config.js (or next.config.ts), add the output: 'standalone' property:
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
};
module.exports = nextConfig;
Step 2: Create a .dockerignore file
Just like a .gitignore file, a .dockerignore file tells Docker what to exclude from the build context. This is crucial for keeping your image size small and your build times fast. You don’t need your node_modules folder or your development files in the final image.
Create a file named .dockerignore in the root of your project and add the following:
.next
node_modules
.git
.gitignore
.DS_Store
README.md
This file prevents unnecessary files from being copied into the Docker build, saving time and disk space.
Step 3: Write the Dockerfile (Multi-Stage Build)
The most effective way to containerize a Next.js app is by using a multi-stage Dockerfile. This process separates the build environment (where dependencies are installed and the app is built) from the runtime environment (where the final, built app is run). This results in a final image that is significantly smaller and more secure.
Create a file named Dockerfile in the root of your project and add the following content:
FROM node:18-slim
WORKDIR /app
COPY .env.local .env.local
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build // Running the build command to prepare the Next.js application
EXPOSE 3000
CMD ["npm", "start"]
RUN npm run build // Running the build command to prepare the Next.js application
EXPOSE 3000
CMD ["npm", "start"]
This is a single build Dockerfile for beginners.
However you can also use Multi Stage build which segregates Build and Production phase.
Below is the example of Multistage Docker Build
# Stage 1: Build the Next.js application
FROM node:18-alpine AS builder
WORKDIR /app
# Copy package.json and package-lock.json to leverage Docker cache
COPY package.json package-lock.json ./
# Install dependencies, avoiding dev dependencies in final image
RUN npm ci
# Copy the rest of the application files
COPY . .
# Build the Next.js app for production
RUN npm run build
# Stage 2: Create the production-ready image
FROM node:18-alpine AS runner
WORKDIR /app
# Set environment variables
ENV NODE_ENV production
# Create a non-root user for security
RUN addgroup --system --gid 1001 nextjs-user && \
adduser --system --uid 1001 nextjs-user && \
chown -R nextjs-user:nextjs-user /app
# Copy the standalone output from the builder stage
COPY --from=builder --chown=nextjs-user:nextjs-user /app/public ./public
COPY --from=builder --chown=nextjs-user:nextjs-user /app/.next/standalone ./
COPY --from=builder --chown=nextjs-user:nextjs-user /app/.next/static ./.next/static
# Expose the port Next.js runs on
EXPOSE 3000
# Set the non-root user
USER nextjs-user
# Command to run the application
CMD ["node", "server.js"]
I will be using the Single build Dockerfile here.
Folder Structure I am using here for the Blog

Step 4: Build and Run Your Docker Image
With your files in place, you’re ready to build and run your Docker container. Open your terminal and navigate to your project’s root directory.
Build the Image
Run the following command to build your Docker image:
docker build -t tumour.io/frontend:v1 .
Here 3000:3000 is the port mapping. So my app will be available at 3000 port.
tumour.io/frontend:v1 is the image name.
Run the Container
Once the image is built, you can run a container from it:
docker run --name tumour.io-frontend -p 3000:3000 tumour.io/frontend:v1
here :
tumour.io-frontend — is the container name.
tumour.io/frontend:v1- is the image name. (This should be same as the image name given in build command).
Access your NextJs App

You can now run your nextjs app at localhost:3000