WarpBuild LogoWarpBuild Docs

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

On this page