Node.js with Vite
Best practices for Dockerfile for Node.js with Vite
🐳 Annotated Dockerfile for Node.js with Vite:
# Use Node.js LTS as the base image for consistency and long-term support
FROM node:lts-slim AS base
# Stage 1: Install dependencies
FROM base AS deps
# Set working directory
WORKDIR /app
# Copy only package definition files first
COPY package.json package-lock.json* ./
# Install dependencies
RUN --mount=type=cache,target=/root/.npm \
npm ci
# Stage 2: Build the application
FROM base AS build
WORKDIR /app
# Copy dependencies
COPY --from=deps /app/node_modules ./node_modules
# Copy source code
COPY . .
# Build the Vite application (outputs to 'dist' folder)
RUN --mount=type=cache,target=/root/.npm \
npm run build
# Stage 3: Production image (using NGINX to serve static files)
FROM nginx:alpine
# Copy Vite build output to NGINX serve directory
COPY --from=build /app/dist /usr/share/nginx/html
# Copy custom NGINX config if needed
# COPY nginx.conf /etc/nginx/conf.d/default.conf
# Add non-root user
RUN addgroup -g 1001 -S appuser && \
adduser -u 1001 -S appuser -G appuser
# Set permissions
RUN chown -R appuser:appuser /usr/share/nginx/html && \
chmod -R 755 /usr/share/nginx/html && \
chown -R appuser:appuser /var/cache/nginx && \
chown -R appuser:appuser /var/log/nginx && \
chown -R appuser:appuser /etc/nginx/conf.d
# Set user
USER appuser
# Expose port
EXPOSE 80
# NGINX will start automatically
CMD ["nginx", "-g", "daemon off;"]
🔍 Why these are best practices for Vite:
✅ Static build output optimization
- Vite produces static files in the
dist
directory that are ideal for serving with NGINX - No need for a Node.js runtime in production for client-side applications
- Much smaller final image size and improved security
✅ Multi-stage build approach
- The final image only contains the built assets, not any source code or dependencies
- Build tools, source code, and node_modules are not included in the production image
- Significantly reduces the attack surface and image size
✅ Dependency caching
- Speeds up repeated builds by caching the npm modules
- Improves CI/CD pipeline efficiency
✅ Non-root NGINX configuration
- Runs NGINX as a non-root user for enhanced security
- Properly sets file permissions for the nginx user
🚀 Additional Vite-specific configurations:
Environment Variables in Vite
Vite handles environment variables differently. Only variables prefixed with VITE_
are exposed to client-side code:
# In the build stage
ARG VITE_API_URL
ENV VITE_API_URL=${VITE_API_URL}
Custom NGINX Configuration
For SPAs (Single Page Applications), you might need this NGINX configuration:
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# SPA routing - redirect all requests to index.html
location / {
try_files $uri $uri/ /index.html;
}
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
}
Save this as nginx.conf
in your project and uncomment the COPY line in the Dockerfile.
Development Setup with Docker Compose
version: "3"
services:
vite:
build:
context: .
target: deps
command: npm run dev -- --host 0.0.0.0
volumes:
- .:/app
- /app/node_modules
ports:
- "5173:5173"
environment:
- VITE_API_URL=http://localhost:8080/api
This approach mounts your local directory for hot-reloading during development.
By following these best practices, your Vite applications will have optimized production builds with minimal container size and maximum security.
Last updated on