TESTED ON: macOS Ventura 14, Ubuntu 22.04, Windows 11 (WSL2 + Native), Node.js v18–v22, npm v9–v10
TL;DR
You are seeing this error because npm is trying to write files to a directory your current user does not own — usually because Node was installed as root or with sudo at some point.
The fastest fix: stop using sudo with npm, then either change your global npm directory or switch to nvm.
| |
Keep reading for platform-specific steps, how to undo sudo damage, and the full decision tree.
What This Error Actually Means
When you run npm install -g some-package and get something like this:
npm ERR! code EACCES
npm ERR! syscall mkdir
npm ERR! path /usr/local/lib/node_modules
npm ERR! Error: EACCES: permission denied
npm is telling you it does not have write access to the directory it is trying to install into. EACCES is a POSIX error code — it stands for Error ACCess. This is not an npm bug. It is the operating system blocking the write.
Why npm Writes to Protected Directories
When Node.js is installed system-wide (via apt, brew without proper setup, or the official installer), the global npm directory defaults to somewhere like /usr/local/lib/node_modules or /usr/lib/node_modules. These are root-owned directories your regular user account cannot write to.
The Root Cause: Global vs. Local Installs
Global installs (the -g flag) are where this almost always happens. Local installs (inside a project’s node_modules) hit this error only when root previously ran npm inside that project directory.
How to Read the Full Error Message
The two most useful lines in the error output are:
path— tells you exactly which directory npm cannot write to.syscall— tells you what operation failed (mkdir,access,open, etc.).
Always check path first. It will tell you which fix applies to your situation.
Quick Diagnosis: Find Your Specific Error Type
Before picking a fix, identify which type of error you have.
| Error Path Contains | Error Type | Go To |
|---|---|---|
/usr/local/lib/node_modules or /usr/lib/node_modules | Global install error | Fix 1 or Fix 2 |
.npm or npm-cache | Cache directory error | Cache Fix section |
Your project folder (e.g. /home/you/myproject/node_modules) | Local project error | Local Project section |
.npmrc or a config path | Prefix or config error | Fix 3 or Troubleshooting |
Fix 1: Change npm’s Default Global Directory (Recommended)
This is the cleanest fix that does not require installing nvm or touching system directories.
Step-by-Step Setup
| |
Verifying It Worked
| |
Fix 2: Use nvm (Node Version Manager)
nvm installs Node and npm inside your home directory from the start, which means it never touches system directories. This sidesteps the permission problem entirely.
Why nvm Sidesteps This Problem
Every Node version nvm installs lives under ~/.nvm/. Your user already owns everything there. No root access is ever needed.
Installing nvm on macOS/Linux
| |
Migrating Global Packages After Switching
| |
Fix 3: Fix Permissions on the Existing npm Directory
Use this only when you cannot change the prefix and cannot use nvm — for example, on a locked-down server.
Finding the Correct Directory
| |
The chown Command
| |
This changes ownership of those subdirectories to your user. After this, npm will write to them without needing sudo.
When This Fix Makes Sense
Use it on a single-user server where you control the environment. Avoid it on shared machines — changing ownership of system directories can affect other users.
Fix 4: Use npx Instead of a Global Install
For many CLI tools, you do not actually need a global install. npx runs a package directly without installing it globally.
| |
Which Tools Work Well with npx
One-time setup tools, scaffolders, and code generators are good candidates: create-react-app, create-next-app, prisma, ts-node, eslint --init.
Limitations
Tools you run constantly from anywhere (like nodemon, pm2, or http-server) are better installed globally since npx re-downloads them each time unless they are already cached.
Platform-Specific Fixes
macOS — Homebrew Users
If you installed Node via Homebrew, the recommended fix is to use nvm instead, or ensure Homebrew’s directories are owned by your user:
| |
Follow any permission repair suggestions brew doctor gives.
macOS — System Node (non-Homebrew)
The system Node that ships with macOS is outdated and not meant for active development. Install Node via nvm or Homebrew and stop using the system version.
Linux — Ubuntu/Debian
If you installed Node via apt, it defaults to root-owned directories. Use nvm, or change the prefix as shown in Fix 1.
| |
Linux — Fedora/RHEL
The same situation applies. dnf install nodejs puts npm in /usr/lib/node_modules. Use nvm or override the prefix.
Windows — WSL2
Inside WSL2, follow the Linux instructions above. nvm works exactly the same way inside a WSL2 terminal.
Windows — Native (cmd / PowerShell)
On native Windows, the error usually points to a path like C:\Users\You\AppData\Roaming\npm. Fix it by taking ownership.
Via GUI:
- Right-click the
npmfolder insideAppData\Roaming - Go to Properties > Security > Edit
- Give your user account Full Control
Via PowerShell (run as Administrator):
| |
Docker and CI/CD Environments
In Docker, this usually happens when the image runs as root and then switches users, or when a volume is mounted with root ownership. Fix it in your Dockerfile:
| |
In CI pipelines (GitHub Actions, GitLab CI), prefer local installs over global ones. If you need global packages, add a prefix config step before the install step.
| |
Fix Cache Permission Errors
If the path in your error contains .npm or _npx, it is a cache issue.
| |
If the cache is stored somewhere else on your system:
| |
Fix Local Project Errors
This happens when someone previously ran sudo npm install inside a project directory, causing node_modules to be owned by root.
Fix Without Deleting node_modules
| |
If That Does Not Work — Clean Reinstall
| |
Do not use sudo on the npm install line once the directory is gone.
Why You Should Never Use sudo npm install -g
Running sudo npm install -g feels like the quick fix, and it works in the moment. But it makes the problem worse over time.
When npm runs with sudo, every file it creates (package directories, binaries, cache entries) is owned by root. Every subsequent npm operation that touches those files will fail for your regular user — meaning you end up needing sudo for more and more things.
What Goes Wrong Over Time
- Your cache directory becomes root-owned, breaking regular installs.
- Binaries installed globally are owned by root, causing issues when packages update themselves.
- Shell scripts and post-install hooks run as root, which is a security risk.
How to Undo sudo Damage
| |
After fixing ownership, switch to one of the permanent solutions above so you never need sudo again.
Prevention
Setting Up .npmrc Correctly
You can lock in your global prefix in an .npmrc file so it persists across sessions:
| |
Project-Level Settings
For projects that should enforce consistent behavior, add a .npmrc at the project root:
| |
CI/CD Best Practices
- Always run npm as a non-root user in Docker.
- Use
npm ciinstead ofnpm installin pipelines — it is faster and more predictable. - Cache your
node_modulesfolder between pipeline runs, not the npm global directory. - Never run
sudo npmin a CI script.
Verify Your Setup Is Clean
After applying any fix, run these to confirm everything is working:
| |
Checking Which npm Config Is Active
| |
Troubleshooting
Check Which User Owns the Problem Directory
| |
Look at the third column — that is the owner. If it says root, you need Fix 1, 2, or 3.
Reset npm to Factory Defaults
| |
Clean Reinstall of Node and npm
If everything is tangled up, a clean slate is often the fastest path forward:
| |
How to Ask for Help Effectively
If you post on Stack Overflow or open a GitHub issue, always include:
- The full error output, not just the last line
- Output of
npm config list - Output of
node -vandnpm -v - How you originally installed Node (apt, brew, nvm, official installer, etc.)
- Your OS and version
Summary and Decision Tree
| Your Situation | Best Fix |
|---|---|
| Fresh setup, no Node yet | Install via nvm |
| Have Node, want the easiest fix | Fix 1 — change prefix |
| On a team or shared server | Fix 1 + commit .npmrc |
| One-time tool usage | Use npx |
| Docker or CI environment | Non-root user + set prefix in Dockerfile |
| Windows native | Take ownership of AppData\Roaming\npm |
| Already ran sudo and broke things | Undo sudo damage first, then Fix 1 or 2 |
| Cache-only error | Fix cache ownership or clear cache |
Local project node_modules error | chown or delete and reinstall |
The single rule that prevents all of this: never use sudo with npm. If npm asks for root access, that is a signal the setup needs to be fixed — not a reason to grant it.
FAQ
Can I just run sudo npm install -g to fix it quickly?
You can, and it will work once. But it makes root own those files, and you will hit the same error again on the next install. It is not a fix — it is a way to make the problem worse over time.
Why does npm default to a root-owned directory in the first place?
When Node is installed system-wide through a package manager like apt or the official installer, it places itself in system directories that are protected by design. npm inherits that location as its default prefix. The solution is to override that default, which is exactly what Fix 1 and nvm both do.
Does this affect npm scripts inside package.json?
No. The EACCES error is specific to global installs and directories your user does not own. npm scripts run in the project directory, which your user already owns.
Will this error appear on a fresh nvm install?
No. nvm installs everything inside your home directory from the beginning. You will not see this error unless you mix a nvm-managed Node with sudo commands.
I fixed it but it came back after a system update. Why?
System updates sometimes reinstall Node or reset directory ownership. If this happens repeatedly, use nvm so Node is fully inside your home directory and out of reach of system package managers.
Does this happen on Windows?
Less often, but yes. On Windows the error usually points to the AppData\Roaming\npm folder rather than a Unix-style path. The fix is to ensure your user account has full control over that folder.
What is the difference between npm install and npm install -g?
npm install (without -g) installs a package into the local node_modules folder inside your current project. npm install -g installs it globally so it is available as a command anywhere on your system. The EACCES error almost always involves the -g flag.