# ============================================================================= # Stage 1: Builder - Install dependencies and build # ============================================================================= FROM node:20-alpine AS builder WORKDIR /app # Copy package files first (better layer caching) COPY package*.json ./ # Install ALL dependencies (including devDependencies for build) RUN npm ci --ignore-scripts # Copy source code COPY . . # Build the application RUN npm run build # ============================================================================= # Stage 2: Production dependencies only # ============================================================================= FROM node:20-alpine AS deps WORKDIR /app COPY package*.json ./ # Install ONLY production dependencies (smaller image) RUN npm ci --omit=dev --ignore-scripts && npm cache clean --force # ============================================================================= # Stage 3: Production - Minimal runtime image # ============================================================================= FROM node:20-alpine AS production # Add non-root user for security RUN addgroup -g 1001 -S nodejs && adduser -S nestjs -u 1001 WORKDIR /app # Copy only what's needed to run COPY --from=deps --chown=nestjs:nodejs /app/node_modules ./node_modules COPY --from=builder --chown=nestjs:nodejs /app/dist ./dist COPY --from=builder --chown=nestjs:nodejs /app/package.json ./ # Set environment ENV NODE_ENV=production ENV PORT=3001 # Use non-root user USER nestjs EXPOSE 3001 # Health check HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD node -e "require('http').get('http://localhost:3001/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))" || exit 1 CMD ["node", "dist/main.js"]