Exit code 137 indicates the Docker container was killed by the OOM (Out of Memory) killer. The fix involves increasing Docker memory limits, optimizing Node.js heap size, or using multi-stage builds.
Exit code 137 in Docker indicates that the container was forcibly terminated with SIGKILL (signal 9) by the kernel's Out-Of-Memory (OOM) killer. When Node.js and npm operations exceed the Docker container's allocated memory limit, the kernel terminates the process immediately without graceful shutdown. This manifests as npm ERR! code ELIFECYCLE with errno 137 because the npm script (like npm install or npm run build) was killed mid-execution. The container's memory limit—either explicitly set via Docker flags or inherited from the host—was exceeded, causing the system to forcibly kill the process. Exit code 137 specifically equals 128 + 9 (SIGKILL), making it distinct from other npm failures. This commonly occurs during dependency installation or build steps in Docker containers, particularly when building large projects with complex dependency trees.
First, confirm that exit code 137 is due to memory:
docker inspect <container_id> --format='{{json .State}}'Look for the OOMKilled field. If it's true, the kernel OOM killer terminated the process.
Check your host system's kernel log for OOM killer messages:
# On Linux hosts
dmesg | tail -20
# Look for "Killed process" messagesOn macOS and Windows, Docker runs inside a lightweight VM with limited memory.
For Docker Desktop on macOS/Windows:
1. Open Docker Desktop → Preferences (macOS) or Settings (Windows)
2. Go to Resources → Memory
3. Increase from the default to at least 4 GB for medium projects, or 8 GB for large projects
4. Apply & restart Docker Desktop
5. Retry your build
For small EC2/cloud instances:
Upgrade to at least t3.medium (4 GB RAM) or add swap space:
# Create 2GB swap file
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfileFor Docker Compose, explicitly set memory limits:
version: "3.9"
services:
app:
build:
context: .
dockerfile: Dockerfile
deploy:
resources:
limits:
memory: 2G
reservations:
memory: 1GFor standalone docker build commands:
docker build --memory=2g --memory-swap=-1 -t my-app .The --memory-swap=-1 flag allows unlimited swap, effectively doubling the available memory.
Node.js's V8 engine defaults to allocating 1.7 GB of heap. Set the NODE_OPTIONS environment variable to limit heap allocation:
# In your Dockerfile
ENV NODE_OPTIONS="--max-old-space-size=1024"
RUN npm install
RUN npm run buildThis sets the maximum V8 heap to 1024 MB (1 GB), leaving room for system processes.
Additionally, optimize npm to use fewer resources:
# Reduce npm's own memory usage
ENV npm_config_max_sockets=1
ENV npm_config_progress=false
RUN npm installMulti-stage builds allow you to discard the build environment after compilation:
# Stage 1: Build with dependencies
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY . .
RUN npm run build
# Stage 2: Runtime (no build tools needed)
FROM node:22-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package*.json ./
EXPOSE 3000
CMD ["node", "dist/index.js"]Enable Docker BuildKit for better caching:
DOCKER_BUILDKIT=1 docker build -t my-app .Docker Memory Management: Docker containers have both memory limits (hard cap) and memory reservations (soft cap). When a process exceeds the hard limit, the kernel OOM killer immediately terminates it with SIGKILL (exit code 137).
Node.js Heap Sizing: The V8 JavaScript engine uses a generational garbage collector. Without explicit limits, it allocates up to ~1.7 GB of heap for 64-bit systems. In containers, V8 doesn't automatically detect the memory limit; setting NODE_OPTIONS="--max-old-space-size=X" tells V8 to trigger garbage collection more frequently.
npm Resolution Algorithm: Modern npm (v7+) performs more aggressive peer dependency resolution, building an in-memory dependency graph before installation. This is more memory-intensive than older npm versions. npm ci uses a lock file and is more deterministic than npm install, resulting in lower peak memory.
False Positives: Exit code 137 doesn't always mean OOM—it indicates SIGKILL but could also result from a Docker daemon timeout or explicit docker stop command. Always check docker inspect to confirm OOMKilled: true.
npm ERR! code E401 npm ERR! 401 Unauthorized - Token has expired
Token has expired - npm authentication failure
npm ERR! code EAI_NODATA npm ERR! errno EAI_NODATA npm ERR! getaddrinfo EAI_NODATA registry.npmjs.org
How to fix "npm ERR! code EAI_NODATA - getaddrinfo EAI_NODATA"
npm ERR! code EMPTYPACKAGE npm ERR! Package contains no files
How to fix 'npm ERR! code EMPTYPACKAGE' - Package contains no files
npm ERR! code EWORKSPACEMISSING npm ERR! Workspace does not exist: packages/missing
How to fix "npm ERR! code EWORKSPACEMISSING - Workspace does not exist" error
npm ERR! code EADDRNOTAVAIL npm ERR! errno EADDRNOTAVAIL npm ERR! Address not available
How to fix "npm ERR! code EADDRNOTAVAIL - Address not available" error