Single stage build

FROM node:20-alpine  
 
WORKDIR /app
 
COPY package*.json ./
 
RUN npm install
 
COPY . .
 
RUN npm run build
 
EXPOSE 3000
 
CMD ["npm", "run", "start"]

Multi-stage build for the same,

# Stage 1: Install dependencies and build the app  
FROM node:20-alpine AS builder  
WORKDIR /app  
COPY package*.json ./  
RUN npm ci  
COPY . .  
RUN npm run build  
  
# Stage 2: Install production dependencies  
FROM node:20-alpine AS production-dependencies  
WORKDIR /app  
COPY package*.json ./  
RUN npm ci --only=production  
  
# Stage 3: Prepare the final image  
FROM node:20-alpine  
WORKDIR /app  
  
# Copy built assets and production dependencies  
COPY --from=builder /app/.next ./.next  
COPY --from=builder /app/public ./public
COPY --from=production-dependencies /app/node_modules ./node_modules  
COPY package*.json ./  
  
# Set proper permissions and user  
RUN chown -R node:node /app  
USER node  
  
EXPOSE 3000  
  
CMD ["npm", "run", "start"]

Advantages

  • Smaller Final Image: Instead of carrying all build tools and dev dependencies, your final image only contains what’s needed to run the application
  • Security: Fewer packages mean smaller attack surface
  • Clean Separation: Build process is separate from runtime environment