How to dockerize Nuxt 3 applications?
A practical walkthrough of Dockerizing a Nuxt 3 application: learn step-by-step how to create a Nuxt project, implement multi-stage builds, optimize Docker images, and set up Docker Compose and NGINX production build.
Introduction
Remember when front-end developers only worried about making websites look good? Those days are gone. Now, frameworks like Nuxt and Next aren't just about pretty interfaces they're full-stack powerhouses that require us to understand way more than just HTML and CSS.
Dockerizing your application has become a must-have skill, and it's not as scary as it sounds. In this friendly guide, we'll break down the process of creating a Nuxt app and turning it into a Docker container.
Requirements
- An existing Nuxt application for dockerization, or create a new Nuxt application.
- Ensure Docker and Docker Compose are installed on you machine by running the following commands:
docker version docker compose version
In this guide, I use npm as package manager, you can use any other that you want.
Note: docker-compose
is the older, standalone Python-based CLI tool that was originally developed as a separate project.
Old way: docker-compose version
New way: docker compose version
Create Dockerfile
At the root of your project, right next to the nuxt.config.ts
file, go ahead and create a Dockerfile
.
Now we can include our instruction that Docker can use to package our application into an image:
# Use Node.js Alpine for build stage with all dev tools
FROM node:22.12.0-alpine AS build
# Set working directory inside the container
WORKDIR /app
# Copy package files for dependency installation
COPY package*.json ./
# Install dependencies using clean install for reproducibility
RUN npm ci
# Copy entire project to container
COPY . .
# Build the Nuxt application
RUN npm run build
# Use distroless Node.js image for production for minimal, secure runtime
FROM gcr.io/distroless/nodejs22-debian12 AS prod
# Set working directory in production container
WORKDIR /app
# Copy built output from build stage to production container
COPY --from=build /app/.output ./.output
# Expose port the app will run on
EXPOSE 3000
# Command to start the Nuxt server from built output
CMD ["./.output/server/index.mjs"]
Create .dockerignore
(Optional)
It's highly recommended to create .dockerignore
file to ignore unnecessary files in your Docker Image. it's very similar to .gitignore
or .eslintignore
.
just next to your Dockerfile
, create a file named .dockerignore
and add the following content:
node_modules
.output
.nuxt
.git
Build and Run Docker Image
Run the following command to build your Docker image:
docker build -t nuxt-docker .
-t nuxt-docker
: This flag tags (names) your Docker image as "nuxt-docker", making it easier to reference later.
tells Docker to use the current directory's Dockerfile as the build context, meaning it will look for the Dockerfile in your current working directory
After building your Docker image, run the following command to start the container:
docker run -p 3000:3000 nuxt-docker
-p 3000:3000
maps the container's port 3000 to your local machine's port 3000- This allows you to access the Nuxt application in your browser at http://localhost:3000
- You can make sure your
3000
port is free before running your container:npx kill-port 3000
Now you can view your Nuxt application running inside a Docker container!
Advanced Command (Optional)
The following command is more practical and advanced to run you docker container.
docker run -d --name nuxt-app -p 3000:3000 --restart unless-stopped nuxt-docker
-d
: Runs the container in detached mode (background mode)--name nuxt-app
: Gives a meaningful name to your container for easier management--restart unless-stopped
: Automatically restarts the container if it crashes or when Docker restarts, unless you manually stop it
Production Build (Docker Compose and NGINX)
This section is optional. If you've already run your Docker container successfully, you can skip it.
However, Docker Compose becomes incredibly useful when you want to orchestrate multiple services, like combining your Nuxt app with a database or backend service, all working together in a single configuration.
Think of Docker Compose as a conductor, managing multiple containers and their interactions with just one command, making complex setups a breeze.
We also use Replica feature in Docker Compose to scale the app horizontally and using NGINX upstream for load balancing.
Create docker-compose.yaml
next to the Dockerfile
and add the following content:
services:
nuxt:
build:
context: .
dockerfile: Dockerfile
target: prod
deploy:
replicas: 3
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
ports:
- "3000-3002:3000"
networks:
- web-network
environment:
- NODE_ENV=production
- PORT=3000
healthcheck:
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://localhost:3000"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
networks:
- web-network
depends_on:
- nuxt
networks:
web-network:
driver: bridge
last but not least, you need to create nginx.conf
file, again, next to the Dockerfile
and add the following content:
events {
worker_connections 1024;
}
http {
upstream nuxt-cluster {
least_conn;
server nuxt:3000;
server nuxt:3001;
server nuxt:3002;
}
server {
listen 80;
location / {
proxy_pass http://nuxt-cluster;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
Build and start the containers
docker compose up --build -d
Check running containers
docker compose ps
Verify the Result
curl http://localhost
# Or open http://localhost in your browser
Conclusion
By leveraging Docker and NGINX, you transform application deployment into a scalable infrastructure. This approach provides horizontal scaling, consistent environments, enhanced security, and improved developer experience. Containerization eliminates "it works on my machine" problems while ensuring high availability and performance.
If you found this guide helpful, please ⭐ the repository - your support means a lot!
Docker and Nuxt.js: Quick Q&A
NGINX acts as a powerful reverse proxy and load balancer, efficiently distributing incoming traffic across multiple Nuxt.js application instances. It handles routing, can implement caching, manages SSL termination, and provides an additional layer of security and performance optimization.
NGINX enables horizontal scaling by intelligently distributing requests across multiple container replicas. It supports advanced load balancing algorithms (like least connections), provides health checks to route traffic only to healthy containers, and can dynamically adapt to changes in your application's infrastructure.
Docker is a platform that allows you to package, distribute, and run applications in isolated environments called containers. It simplifies deployment by ensuring consistency across different development and production systems.
Multi-stage builds let you create more efficient Docker images by using multiple FROM
statements. Each stage can copy specific artifacts from previous stages, resulting in smaller final images with only necessary components.
A container is a lightweight, standalone, executable package that includes everything needed to run an application: code, runtime, system tools, libraries, and settings. It's essentially a running instance of a Docker image.
Docker provides consistent environments, simplifies deployment, enables easy scaling, and isolates your Nuxt.js application. It helps manage dependencies, ensures identical setups across different machines, and supports seamless continuous integration.
Distroless images are minimal container images that contain only your application and its runtime dependencies, without package managers, shells, or other system tools. They improve security by reducing the attack surface and image size.
A replica is a copy of a container running the same service. In Docker Compose or Swarm, replicas allow you to scale applications horizontally, distribute load, and provide high availability by running multiple identical instances.
Docker standardizes deployment by packaging applications with all dependencies, enables quick scaling, supports microservices architecture, and provides consistent environments from development to production.
Yes, Docker can improve Nuxt.js performance through efficient container management, easy horizontal scaling, load balancing, and simplified deployment of optimized production builds.
By copying package files first and installing dependencies before copying the full project, you leverage Docker's layer caching. This means if your package.json
hasn't changed, Docker can reuse the cached dependency layer, making subsequent builds much faster. It's a performance optimization that prevents reinstalling packages on every build when your code changes.