# Multi-stage Dockerfile for Next.js 14 app (production) FROM node:20-bullseye AS builder WORKDIR /app # Copy only package manifests first for better caching COPY package.json package-lock.json* ./ RUN npm ci --silent # Copy rest of the source COPY . ./ # Build the app ENV NODE_ENV=production RUN npm run build # Remove dev dependencies to keep final node_modules small RUN npm prune --production --silent || true FROM node:20-bullseye-slim AS runner # Create non-root user to run the app (only if it doesn't exist) # Some base images already contain UID 1000 or the same user, so avoid fixed UID. RUN id -u nextjs >/dev/null 2>&1 || (groupadd -r nextjs && useradd -r -g nextjs nextjs) WORKDIR /app # Copy minimal runtime files from builder COPY --from=builder /app/package.json ./ COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/.next ./.next COPY --from=builder /app/public ./public COPY --from=builder /app/next.config.mjs ./next.config.mjs # Ensure app files are owned by non-root user RUN chown -R nextjs:nextjs /app ENV NODE_ENV=production # Expose (container runtime will map $PORT). Default to 3000 if not provided. EXPOSE 3000 # Run as non-root user USER nextjs # Use shell form so $PORT is expanded at runtime; provide fallback to 3000 when empty CMD ["/bin/sh", "-lc", "echo 'Starting app; using PORT='${PORT:-7860} && echo \"NEXT_PUBLIC_SUPABASE_URL set: ${NEXT_PUBLIC_SUPABASE_URL:+yes}\" && echo \"NEXT_PUBLIC_SUPABASE_ANON_KEY set: ${NEXT_PUBLIC_SUPABASE_ANON_KEY:+yes}\" && echo \"SUPABASE_SERVICE_ROLE_KEY set: ${SUPABASE_SERVICE_ROLE_KEY:+yes}\" && npm run start -- -p ${PORT:-7860}"]