状況
新しいMacをセットアップしているとき、またはプロジェクトにオンボーディングしているとき、いつものように npm install -g を実行すると、こんなエラーに見舞われます:
npm ERR! code EACCES
npm ERR! syscall access
npm ERR! path /usr/local/lib/node_modules
npm ERR! errno -13
npm ERR!
npm ERR! Error: EACCES: permission denied, access '/usr/local/lib/node_modules'
npm ERR! [Error: EACCES: permission denied, access '/usr/local/lib/node_modules'] {
npm ERR! errno: -13,
npm ERR! code: 'EACCES',
npm ERR! syscall: 'access',
npm ERR! path: '/usr/local/lib/node_modules'
npm ERR! }
npm ERR! The operation was rejected by your operating system.
Stack Overflowの多くの回答が提案する解決策——頭に sudo をつける——は技術的には動作しますが、後々さらに厄介な問題を引き起こします。rootとしてインストールされたグローバルパッケージはユーザー環境と競合し、後でさらに多くの権限問題を招く可能性があります。
正しい解決策は3つあります。自分の環境に合ったものを選んでください。
なぜこのエラーが起きるのか
Node.jsを公式の .pkg インストーラー、または一部のHomebrewのセットアップでインストールした場合、グローバルモジュールは /usr/local/lib/node_modules に配置されます。macOS(特にSIPが有効なCatalina以降)では、デフォルトでユーザーアカウントはそのディレクトリへの書き込み権限を持っていません。そのため、npmがそこに書き込もうとした瞬間、OSがブロックします。
ディレクトリの所有者を確認してみましょう:
ls -la /usr/local/lib/ | grep node_modules
所有者が root になっていれば、それが問題の原因です。
解決策1:nvmに切り替える(恒久的な解決策)
これが長期的に正しいアプローチです。nvm(Node Version Manager)はNodeをホームディレクトリ内に完全にインストールするため、npmがどんな操作をするときもroot権限が不要になります。
# nvmをインストール
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# シェルの設定を再読み込み
source ~/.zshrc # bashを使っている場合は ~/.bashrc
# 必要なNodeのバージョンをインストール
nvm install --lts
nvm use --lts
# nvmが管理するnodeを使っていることを確認
which node
# 次のような出力になるはずです: /Users/yourname/.nvm/versions/node/v20.x.x/bin/node
切り替え後は、権限の問題なしにグローバルインストールが可能になります:
npm install -g typescript
npm install -g pnpm
注意点として、以前にNode.jsをシステム全体にインストールしていた場合、PATH がnvm版のNodeを優先して参照するようにしてください。which node と node --version を実行して確認しましょう。
解決策2:npmのグローバルプレフィックスをユーザーディレクトリに変更する
現在のNodeインストールを維持する必要がある場合(またはNodeのセットアップを変更できないチームのマシンを使っている場合)、npmのグローバルパッケージディレクトリをユーザーが所有する場所にリダイレクトします。
# グローバルnpmパッケージ用のディレクトリを作成
mkdir -p ~/.npm-global
# nvmにそのディレクトリを使うよう設定
npm config set prefix '~/.npm-global'
# PATHに追加 — この行を ~/.zshrc または ~/.bash_profile に追記
export PATH=~/.npm-global/bin:$PATH
# 再読み込み
source ~/.zshrc
設定が反映されたか確認します:
npm config get prefix
# 次のような出力になるはずです: /Users/yourname/.npm-global
グローバルインストールをテストしてみましょう:
npm install -g nodemon
nodemon --version
解決策3:既存ディレクトリの所有権を修正する
この方法は、マシンの唯一のユーザーであり、NodeやNpmの設定を変更したくない場合にのみ使用してください。/usr/local/lib/node_modules の所有者を自分自身に変更します。
# ユーザー名を確認
whoami
# 所有権を変更('yourname'を実際のユーザー名に置き換えてください)
sudo chown -R yourname /usr/local/lib/node_modules
sudo chown -R yourname /usr/local/bin
共有マシンではこの方法に注意してください——システムディレクトリをユーザーアカウントから書き込み可能にしているためです。個人用の開発Macであれば問題ありませんが、トレードオフを理解した上で使用してください。
動作確認
いずれかの解決策を適用した後、すべてが正常に動作しているか確認します:
# EACCESエラーなしで完了するはずです
npm install -g eslint
# バージョン番号が出力されるはずです
eslint --version
# グローバルパッケージが今どこにインストールされているか確認
npm root -g
npm bin -g
npm bin -g が $PATH に含まれるパスを指していれば、設定は完了です。
ヒント:権限の仕組みを理解する
複数のディレクトリにまたがってトラブルシューティングしている場合や、設定すべき権限を理解しようとしている場合は、ToolCraftのUnix Permissions Calculator がchmod値を視覚的に把握するのに便利です。8進数を頭の中で変換せずに、素早く正しいパーミッションビットを調べる必要があるときに活用しています。
現場からの教訓
- 日常的な解決策として
sudo npm install -gは絶対に使わないこと。一度は動きますが、rootが所有するファイルを生成してしまい、以降のインストールでsudoなしでは失敗するという悪循環を招きます。 - nvmが個人マシンでのデフォルトの選択肢です。
.nvmrcファイルを使ってプロジェクトごとにNodeのバージョンを切り替えられる点も、それだけで導入する価値があります。 - プレフィックス変更のアプローチ(解決策2)は、Nodeのインストールを自分でコントロールできない会社のマシンで作業する場合に最適です。
- 新しいMacをセットアップして既存のdotfilesリポジトリをクローンする場合、
.zshrcのPATH設定がシステムPATHより前に適用されるようにしてください——そうしないとnvmのインストールがシステムのNodeに隠れてしまいます。

