npm EACCES permission denied (tested)

npm error code EACCES / permission denied, mkdir ... means the Node.js process running npm doesn't have write access to the folder it needs — almost always npm's own global install location. We reproduced it exactly by making a directory read-only and installing into it.

1. The error, reproduced

We created a directory, removed write permission from it (chmod 555), and ran a global install against it with --prefix:

$ npm install -g --prefix /tmp/noperm is-odd
npm error code EACCES
npm error syscall mkdir
npm error path /tmp/noperm/lib/node_modules/is-odd
npm error errno -13
npm error Error: EACCES: permission denied, mkdir '/tmp/noperm/lib/node_modules/is-odd'
npm error     at async mkdir (node:internal/fs/promises:1564:10)
npm error The operation was rejected by your operating system.

The path line in the error tells you exactly which directory npm couldn't write to. In real life that's usually npm's configured global prefix, check it with:

$ npm config get prefix

2. Why this happens by default on Linux/macOS

Without any configuration, npm's default global prefix on Linux and macOS is /usr/local (or wherever Node itself was installed) — a directory your regular user account doesn't own. Every npm install -g then tries to write into a root-owned folder and fails with exactly the error above. This box doesn't hit that: it already has a per-user prefix configured in ~/.npmrc, which is the actual fix, not a workaround:

$ cat ~/.npmrc
prefix=~/.npm-global

$ npm config get prefix
/home/jacque/.npm-global

3. The fix: a user-owned prefix (no sudo)

Don't use sudo npm install -g. It "fixes" the immediate error but leaves files in your home directory and cache owned by root, which causes a different, more confusing set of permission errors later. Instead, point npm at a folder you own:

mkdir -p ~/.npm-global
npm config set prefix '~/.npm-global'

Then add that folder's bin to your PATH (in ~/.bashrc or ~/.zshrc), so globally installed CLI tools are found:

export PATH="$HOME/.npm-global/bin:$PATH"

Reload your shell and global installs go to a folder you fully own — no permission error, ever, for this cause.

4. Other EACCES causes, same symptom

In every case the path field in npm's own error output is the fastest way to confirm which directory is actually the problem before trying any fix.

Frequently asked questions

Should I just run npm install with sudo to fix EACCES?

We don't recommend it. It removes the symptom once but leaves root-owned files in your npm cache and sometimes your home directory, which causes a different, harder-to-diagnose permission error later. The fix we measured — a user-owned prefix via npm config set prefix — avoids root ownership entirely.

How do I know which directory npm actually failed to write to?

Read the "path" line in npm's own error output. We reproduced it: npm error path /tmp/noperm/lib/node_modules/is-odd told us exactly which directory lacked write permission, before we tried anything.

I already ran sudo npm install once. How do I undo the damage?

Reclaim ownership of npm's cache: sudo chown -R $(whoami) ~/.npm (run once). That's the one legitimate use of sudo in this whole topic — to undo a previous sudo npm run, not to work around EACCES going forward.

Does this affect npm install without -g too?

Local (non-global) npm install writes into your project's own node_modules, which you almost always own, so EACCES there usually means something else wrote root-owned files into node_modules first (often a Docker build). Delete node_modules and reinstall, or chown -R $(whoami) node_modules.

Does switching Node.js version managers (nvm, fnm, volta) fix this?

Yes, indirectly: they install Node (and npm's global prefix) entirely inside your home directory, so you never hit a root-owned prefix in the first place. If you're not ready to switch managers, setting prefix manually (section 3) achieves the same result.

Written with AI assistance. Measured on 2026-10-02 with npm 11.19.0 and Node.js 24.21.0 on Linux, in a throwaway /tmp directory. npm is free and bundled with Node.js.