[Fixed] npm ERR! code EACCES: permission denied in npm: Step-by-Step Troubleshooting Guide

Executive Summary & Root Cause Analysis: The error npm ERR! code EACCES (syscall open / mkdir / access, permission denied) occurs when running npm install -g <package> on macOS or Linux. By default, system-wide Node.js installations place global packages inside root-owned directories such as /usr/local/lib/node_modules or /usr/lib/node_modules. Because standard user accounts lack write permissions to these system paths, npm aborts the installation. Common triggers include: (1) installing Node.js via official OS installers or system package managers (APT/DNF) rather than a user-space version manager, (2) previously running sudo npm install, which leaves root-owned files inside your local ~/.npm cache, and (3) restrictive permissions on CI/CD or shared build servers.

Step 1: Recommended Fix – Reinstall Node.js Using a Version Manager (NVM)

The official npm-recommended long-term solution is managing Node.js through a Node Version Manager (such as nvm on Linux/macOS or nvm-windows on Windows). Version managers install Node.js and all global packages directly inside your user home directory, eliminating system permission conflicts completely.

# Install NVM (Linux / macOS)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash

# Reload your shell configuration (Bash or Zsh)
source ~/.bashrc   # or: source ~/.zshrc

# Install and activate the latest LTS release of Node.js
nvm install --lts
nvm use --lts

# Install your global package without sudo
npm install -g <package-name>

Step 2: Configure a User-Owned Global Directory for npm

If you prefer to keep your existing system-wide Node.js installation without switching to NVM, reconfigure npm’s global prefix to point to a hidden folder inside your home directory:

# 1. Create a directory for global npm installations
mkdir -p ~/.npm-global

# 2. Configure npm to use the new directory path
npm config set prefix '~/.npm-global'

# 3. Add the new global bin path to your shell profile (~/.bashrc, ~/.zshrc, or ~/.profile)
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.profile

# 4. Reload your shell profile
source ~/.profile

# 5. Test global installation cleanly
npm install -g <package-name>

Step 3: Alternative Workarounds – Cache Ownership & npx

If the EACCES error occurs during a local npm install (not global) or inside ~/.npm, or if you only need to run a CLI tool once:

  1. Repair ownership of your local npm cache and node_modules:
    # Fix root-owned files left behind by prior 'sudo npm' commands
    sudo chown -R $(whoami):$(id -gn) ~/.npm
    sudo chown -R $(whoami):$(id -gn) ./node_modules
  2. Use npx to run CLI tools without global installation:
    # Execute CLI packages directly without modifying global directories
    npx <package-name> <arguments>

Verification & Testing Steps

Confirm that npm resolves global installations to a user-writable path and executes installed binaries without permission errors:

# Verify the active npm global prefix points to your home directory
npm config get prefix

# Confirm where global binaries are resolved in PATH
which <installed-cli-command>

# Run a test global install and check package list
npm list -g --depth=0

Summary Comparison Table

Resolution Method How It Works Security & Stability Best Used For
Node Version Manager (nvm) Installs Node & global packages in user home dir Highest (Zero sudo needed, easy version switching) Local development machines
Custom npm prefix (~/.npm-global) Redirects global package path to user directory High (Preserves system Node binary) Servers or locked-down environments
sudo chown -R on ~/.npm Fixes ownership of corrupted cache/local folders High (Repairs prior sudo npm damage) Local npm install cache errors
npx <package> Downloads & runs CLI tools ephemerally Highest (No global state modified) One-off scaffolding & build scripts

Leave a Reply