Fix: npm Permission Denied
Global installs fail because npm can't write to its install directory. Here's the permanent fix — and why sudo makes it worse.
Last updated: October 2026
Don't use sudo. Configure npm to install globals in your home folder instead:
# 1. Create a directory for global packages
mkdir ~/.npm-global
# 2. Tell npm to use it
npm config set prefix '~/.npm-global'
# 3. Add it to your PATH
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.zshrc # macOS / zsh
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc # Linux / bash
# 4. Reload your shell
source ~/.zshrc # or source ~/.bashrc
# 5. Test — should work without sudo
npm install -g typescript
This solves the problem permanently. No more permission errors, ever.
Why sudo makes it worse
The most common "fix" is to run sudo npm install -g package. It works — until you hit the next problem, which is worse.
What happens when you use sudo:
- Files inside
/usr/local/lib/node_modulesget owned byroot - Your user can no longer modify or uninstall them without sudo
- Subsequent non-sudo installs fail with EACCES because they can't write to the root-owned directory
- You have to keep using sudo forever, escalating the mess
Never use sudo for npm. It's a trap. The fix always comes back to "make npm use a directory you own." Do that instead.
If you already used sudo: You may have mixed ownership in /usr/local/lib/node_modules and /usr/local/bin. You'll need to fix it. See the "Recovery" section below.
Three fixes, in order of preference
Recommended — use nvm (Node Version Manager)
nvm installs Node and npm into your home directory. No system directories involved, no permission issues, ever. It also lets you switch Node versions per project.
# Install nvm (macOS/Linux)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
# Or with Homebrew
brew install nvm
# Reload your shell
source ~/.zshrc # or ~/.bashrc
# Install latest Node LTS
nvm install --lts
# Verify
which npm # → ~/.nvm/versions/node/v22.x/bin/npm
npm install -g typescript # no sudo, no errors
Windows users: Use nvm-windows from github.com/coreybutler/nvm-windows. Same benefits.
Alternative — change npm's global prefix
If you don't want to install nvm, this is the manual version. Same result.
# Create a global directory in your home
mkdir ~/.npm-global
# Point npm at it
npm config set prefix '~/.npm-global'
# Add to PATH — check which shell you use
echo $SHELL
# For zsh (macOS default)
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.zshrc
source ~/.zshrc
# For bash (Linux default)
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
# Verify it worked
echo $PATH | grep npm-global
npm config get prefix
Recovery — fix ownership after using sudo
If you already used sudo and mixed ownership, fix it first, then apply fix #1 or #2.
# macOS / Linux — reclaim ownership of npm's global directory
sudo chown -R $(whoami) $(npm config get prefix)/{lib/node_modules,bin,share}
# Verify
ls -la $(npm config get prefix)/lib/node_modules
# Owner should now be your user, not root
# Then switch to ~/.npm-global (fix #2) to prevent this recurring
One-time sudo, then never again. The chown command is legitimately the only place sudo belongs in this workflow.
Diagnose which permission issue you have
# 1. Where does npm want to install globals?
npm config get prefix
# If this returns /usr/local or /usr/lib, that's the problem
# If it returns something in your home directory, permissions should work
# 2. Who owns the prefix directory?
ls -la $(npm config get prefix)
# Look for "root" as the owner — that's why you can't write
# 3. What's your shell?
echo $SHELL
# 4. Is ~/.npm-global/bin already on PATH?
echo $PATH | grep npm-global
# 5. Have you used sudo before? Check for root-owned files
find ~/.npm -not -user $(whoami) 2>/dev/null | head
🛡️ How to avoid npm permission issues forever
- Use nvm. It's the cleanest solution. Everything lives in your home folder, no permissions conflicts possible.
- Never run
sudo npm install. If you see permission errors, fix the prefix instead. It's a 2-minute fix that never comes back. - Prefer local installs. Most tools don't need to be global. Use
npxfor one-off CLI tools instead of global installs. - Use
npm ciin CI. Clean install from lockfile, always in a fresh environment. - Back up your PATH config. Before editing
.zshrcor.bashrc, save a copy. Small mistakes there break every terminal command.
❓ Frequently asked questions
How do I fix npm EACCES permission denied?
The permanent fix: create a directory for global packages in your home folder, tell npm to use it, and add it to your PATH. This avoids sudo entirely. Commands: mkdir ~/.npm-global, npm config set prefix ~/.npm-global, add export PATH=~/.npm-global/bin:$PATH to your shell profile.
Should I use sudo to fix npm permission errors?
No. Using sudo for npm installs creates files owned by root in your project or global directories. This causes worse permission errors later. The correct fix is to configure npm to install in a directory your user owns.
What is the difference between local and global npm installs?
Local installs (npm install package-name) put packages in ./node_modules inside your project. Global installs (npm install -g package-name) put packages in a system-wide location for CLI tools. EACCES typically happens with global installs.
How do I fix ownership of npm's global directory?
If you've already used sudo and mixed ownership, fix it with: sudo chown -R $(whoami) $(npm config get prefix)/{lib/node_modules,bin,share} on macOS/Linux. Then switch to the ~/.npm-global approach to avoid this in the future.
What is nvm and does it fix npm permissions?
nvm (Node Version Manager) installs Node and npm into your home directory. This avoids permission issues entirely because everything is user-owned. It also lets you switch Node versions per project. Highly recommended as a permanent fix.