How to fix EACCES: permission denied, open '/app/node_modules' in Docker

DockerINTERMEDIATEMEDIUMUpdated Dec 6, 2025ยท 192 views

The EACCES permission denied error occurs when a process inside a Docker container lacks write access to a directory, typically node_modules. This commonly happens due to UID/GID mismatches between the host and container or incorrect ownership after switching users in a Dockerfile.

Quick fix

Fixes EACCES

# Check the user in a running container
docker exec <container_name> whoami

# Check the user ID and group ID
docker exec <container_name> id
  1. Identify which user is running the process
  2. Check file ownership in the container
  3. Fix Dockerfile ordering: install dependencies as root, then switch user
  4. Pre-create directories with correct ownership
docker โ€” error
# Check the user in a running container
docker exec <container_name> whoami
# Check the user ID and group ID
docker exec <container_name> id
EACCES: permission denied, open '/app/node_modules'

What this error means

The EACCES (Error: Access) permission denied error in Docker indicates that the process running inside your container does not have sufficient filesystem permissions to read, write, or execute files in the specified directory. This error is extremely common in Node.js applications running in Docker, particularly when: - You switch to a non-root user with the USER directive but the application directories are still owned by root - You mount a volume from the host where the file ownership doesn't match the container's user ID - npm or yarn tries to create cache directories (like node_modules/.cache) but the user lacks write permissions The error typically appears during npm install, when starting a development server (like webpack-dev-server or Vite), or when the application tries to write to node_modules at runtime.

Typical symptoms

  • npm install fails with EACCES errors
  • Application crashes on startup with permission denied errors
  • Development server fails to create .cache directories
  • Build process fails when trying to write to node_modules
  • Hot reload stops working due to inability to write cache files
  • Commands work with sudo but fail as non-root user

Common causes

  1. COPY command creates files owned by root before USER directive switches to non-root user
  2. Volume mount from host has different UID/GID than the container user
  3. WORKDIR creates directory with wrong ownership when declared after USER
  4. npm/yarn trying to create .cache directory in a root-owned node_modules
  5. Build running as root but CMD running as non-root user without proper chown
  6. Host node_modules folder mounted into container overrides container's node_modules

How to fix "EACCES: permission denied, open '/app/node_modules'"

1Identify which user is running the process

First, check which user your container process runs as:

bash
# Check the user in a running container
docker exec <container_name> whoami

# Check the user ID and group ID
docker exec <container_name> id

This will show you the UID and GID of the running process, which you'll need to match with file ownership.

2Check file ownership in the container

Inspect the ownership of the problematic directory:

bash
# Check ownership of node_modules
docker exec <container_name> ls -la /app/

# Check ownership of specific subdirectory
docker exec <container_name> ls -la /app/node_modules/

If files are owned by root:root but your process runs as a different user (e.g., node with UID 1000), that's the cause of the permission error.

3Fix Dockerfile ordering: install dependencies as root, then switch user

The most reliable fix is to install dependencies as root and switch users only at the end:

dockerfile
FROM node:20-alpine

WORKDIR /app

# Copy package files and install as root
COPY package*.json ./
RUN npm ci

# Copy application code
COPY . .

# Create non-root user and set ownership
RUN addgroup -g 1001 -S nodejs \
    && adduser -S nodejs -u 1001 -G nodejs \
    && chown -R nodejs:nodejs /app

# Switch to non-root user only for runtime
USER nodejs

CMD ["node", "server.js"]

This ensures all files are properly owned by the runtime user.

4Pre-create directories with correct ownership

If you must run npm install as a non-root user, pre-create the directories:

dockerfile
FROM node:20-alpine

# Create user first
RUN addgroup -g 1001 -S nodejs \
    && adduser -S nodejs -u 1001 -G nodejs

WORKDIR /app

# Pre-create node_modules with correct ownership
RUN mkdir -p /app/node_modules \
    && chown -R nodejs:nodejs /app

USER nodejs

COPY --chown=nodejs:nodejs package*.json ./
RUN npm ci

COPY --chown=nodejs:nodejs . .

CMD ["node", "server.js"]

The --chown flag on COPY ensures files are owned by the correct user.

5Fix volume mount permissions for development

When using bind mounts for development, ensure the host directory permissions match:

yaml
# docker-compose.yml
services:
  app:
    build: .
    volumes:
      - .:/app
      - /app/node_modules  # Anonymous volume for node_modules
    user: "1000:1000"  # Match your host user's UID:GID

Find your host UID/GID with:

bash
id -u  # UID
id -g  # GID

Using an anonymous volume for node_modules prevents host/container conflicts.

6Use anonymous volume to isolate node_modules

The cleanest solution for development is to use an anonymous volume for node_modules:

yaml
services:
  app:
    build: .
    volumes:
      - .:/app                # Mount source code
      - /app/node_modules     # Anonymous volume (container's node_modules)

This ensures:
- Source code changes sync from host to container
- Container uses its own node_modules (installed during build)
- No permission conflicts between host and container

Advanced notes

Understanding UID/GID Mapping

Docker containers on Linux share the host's kernel, so file permissions are based on numeric UIDs/GIDs, not usernames. The "node" user in a container (UID 1000) is the same as UID 1000 on the host, regardless of the username.

Rootless Docker and User Namespaces

If you're running rootless Docker or using user namespaces, UIDs are remapped. The container's UID 1000 might map to UID 101000 on the host. Check your Docker configuration with:

bash
cat /etc/subuid
cat /etc/subgid

BuildKit and Cache Mounts

With Docker BuildKit, you can use cache mounts to speed up builds while avoiding permission issues:

dockerfile
# syntax=docker/dockerfile:1
RUN --mount=type=cache,target=/root/.npm \
    npm ci

Security Considerations

Never use chmod 777 as a permanent fix. While it makes the error go away, it allows any user to read, write, and execute files, which is a security risk. Always use proper ownership (chown) instead.

Frequently asked questions

What does "EACCES" mean?
The EACCES (Error: Access) permission denied error in Docker indicates that the process running inside your container does not have sufficient filesystem permissions to read, write, or execute files in the specified directory. cache) but the user lacks write permissions The error typically appears during npm install, when starting a development server (like webpack-dev-server or Vite), or when the application tries to write to node_modules at runtime.
How do I fix "EACCES"?
The EACCES permission denied error occurs when a process inside a Docker container lacks write access to a directory, typically node_modules. This commonly happens due to UID/GID mismatches between the host and container or incorrect ownership after switching users in a Dockerfile.
What causes "EACCES"?
COPY command creates files owned by root before USER directive switches to non-root user Volume mount from host has different UID/GID than the container user WORKDIR creates directory with wrong ownership when declared after USER
Is the "EACCES" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading