Dockerfile by Example: Node Application Image
Node.js images benefit from production settings and deterministic installs. This sample code shows how to use NODE_ENV and npm ci.
Code
FROM node:18-alpine
WORKDIR /app
# 1. Set NODE_ENV to production
# Optimizes dependencies and disables dev features
ENV NODE_ENV=production
# 2. Install dependencies
COPY package*.json ./
# npm ci is faster and more reliable than npm install for builds
RUN npm ci --only=production
COPY . .
USER node
CMD ["node", "server.js"]Explanation
For Node.js applications, setting NODE_ENV=production is a critical optimization. It instructs many libraries (like Express) to cache views, disable verbose error messages, and optimize performance. It also ensures that npm install (or npm ci) skips devDependencies, keeping the image size minimal.
Node.js Docker best practices:
- Use
npm ciinstead ofnpm installfor reproducible builds - Set
NODE_ENV=productionfor performance and security - Run as the built-in
nodeuser instead of root - Use
node:alpinevariants for smaller footprint
The command npm ci (Clean Install) is preferred over npm install in CI/CD and Docker environments. It strictly follows the package-lock.json file, ensuring that the exact same dependency versions are installed every time. It also deletes the existing node_modules folder before installation, preventing inconsistencies. This leads to faster, more reliable, and deterministic builds.
Code Breakdown
ENV NODE_ENV=production enables production optimizations.npm ci --only=production installs only runtime dependencies.USER node enforces least privilege execution.node:18-alpine is a lightweight base image for Node.js.
