This documentation provides a step-by-step guide to prepare a Next.js app and dockerizing it for deploying it to any
cloud using LocalOps.
Prerequisites
To follow this tutorial, you will need the following:
- Node.js, version 18.x or later at the time of writing.
- npm, as a package manager for installing and maintaining dependencies. This usually comes bundled with Node.js.
- A foundational knowledge of Next.js.
- Docker to build standalone containers to serve your production app.
This guide assumes that you have basic knowledge of the above-mentioned technologies and tools. If you are not
familiar with any of them, it is recommended to review their official documentation and tutorials to get up to speed
before proceeding with this guide.
Scaffolding the Next.js app
Next.js offers a CLI tool to quickly scaffold a new project. Run the following command:
npx create-next-app@latest
Follow the prompts to create your app. Refer to the
Next.js Getting Started guide to learn more about scaffolding the app.
Once the application is ready, navigate to the directory and install all the dependencies (if not already installed):
cd your-nextjs-app # replace with the name of the project you created
npm install
Once the dependencies are installed, you can start the dev server by running:
This usually starts the server on port 3000
. Go to http://localhost:3000 to see your app. The
dev server supports hot reloading, so it reloads the application when you make changes.
Building and Dockerizing a Next.js App
When it is time to deploy your app for production, simply run:
This command builds an optimized production bundle. The output is found in the .next
directory.
Once built, you can preview the production build using npm run start
to start a local production server.
Create the Docker Image
Below is a Dockerfile optimized for Next.js, using multi-stage builds for smaller images and best practices for
dependency management.
# syntax=docker.io/docker/dockerfile:1
FROM node:18-alpine AS base
# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED=1
RUN \
if [ -f yarn.lock ]; then yarn run build; \
elif [ -f package-lock.json ]; then npm run build; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
else echo "Lockfile not found." && exit 1; \
fi
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
# Uncomment the following line in case you want to disable telemetry during runtime.
# ENV NEXT_TELEMETRY_DISABLED=1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
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
# server.js is created by next build from the standalone output
# https://nextjs.org/docs/pages/api-reference/config/next-config-js/output
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]
Now you can build and run the Docker image. To build the Docker image:
docker build --platform linux/amd64 -t nextjs-app:latest .
This command builds the nextjs-app
image for the platform linux/amd64
and tags it as latest
.
If you are locally testing your application, you can skip the platform
key to build the images.
# only for testing in a local machine
docker build -t nextjs-app:latest .
Run the Docker Image
Letβs run the Docker container using the image created of the Next.js application with the command below.
docker run \
-it \
--rm \
--name nextjs-app \
-e PORT=3000 \
-d \
-p 3000:3000 \
nextjs-app
-it
: enables interactivity with TTY.
--rm
: tells the Docker Daemon to clean up the container and remove the file system after the container exits.
--name nextjs-app
: Name of the container nextjs-app
.
-e PORT=3000
: Sets the environment variable PORT in Docker to 3000
.
-d
: Runs the container in detached (background) mode. You can skip the flag to see the logs directly in your
terminal window.
-p 3000:3000
: Maps port 3000 on your host to port 3000 in the container.
nextjs-app
at the end is the name of the image.
After running the command, visit http://localhost:3000
to see the Next.js application running inside the Docker
container.
Hurray π. Now we have created and packaged a Next.js app for production use.
Example app
Source: https://github.com/vercel/next.js/tree/canary/examples/with-docker
You can refer to the with-docker
example, which is an official example published by the Next.js team.
Done π
You can now commit and push the Dockerfile to your git repo. Create a service to point
at the git repository and branch name to deploy this image.