Homebrew, pyenv, nvm을 같이 쓰다 보면 같은 PATH를 서로 앞쪽에 넣으면서 brew는 보이는데 python이 안 바뀌거나, nvm은 설치했는데 node가 예전 경로를 계속 가리키는 식의 문제가 자주 생깁니다. 특히 macOS에서 기본 셸이 zsh라면 .zprofile.zshrc 역할을 나눠서 정리하는 편이 가장 빠릅니다.


예시는 macOS의 zsh 기준으로 잡았습니다. 핵심은 Homebrew처럼 로그인 환경에서 먼저 잡아두면 좋은 설정은 .zprofile에 두고, pyenv·nvm처럼 인터랙티브 셸에서 쓰는 버전 전환 설정은 주로 .zshrc에 모으는 것입니다. 이 순서만 정리해도 설치 오류와 실행 오류가 한 번에 줄어드는 경우가 많습니다.


Homebrew, pyenv, nvm을 함께 쓸 때 PATH와 zshrc 수정 순서를 정리한 맥 터미널 콘셉트 대표이미지

Homebrew·pyenv·nvm PATH 정리 흐름을 한눈에 보여주는 대표 이미지


왜 Homebrew·pyenv·nvm을 같이 쓰면 PATH가 꼬일까

세 도구 모두 PATH에 관여하지만 목적이 조금씩 다릅니다. Homebrew는 패키지 관리자라서 실행 파일과 셸 보조 경로를 잡아주고, pyenv는 python, pip 같은 명령을 자기 shims로 먼저 받게 만들며, nvm은 셸 안에서 동작하는 함수로 로드된 뒤 현재 선택된 Node 경로를 반영합니다. 문제는 이 셋을 여러 파일에 중복으로 넣거나, 같은 도구의 예전 설정과 새 설정이 섞일 때 생깁니다.


Node 설치 기준이 아직 애매하다면 Node.js 설치 3가지 비교(2026): nvm vs Homebrew vs 공식 설치(pkg)처럼 먼저 어떤 방식으로 관리할지 정해두는 편이 좋습니다. Homebrew로도 Node를 설치하고 nvm으로도 버전을 바꾸기 시작하면, 어느 쪽이 기본 node인지 헷갈리기 쉬워집니다.


세 도구가 PATH에 끼어드는 방식이 다르다

Homebrew는 설치된 prefix를 기준으로 bin, sbin, completion 경로를 셸에 반영합니다. pyenv는 ~/.pyenv/shims를 PATH 앞쪽에 두고, 같은 shims 경로가 여러 번 들어가면 정리해 주는 방식으로 동작합니다. nvm은 실행 파일이 아니라 sourced shell function에 가깝기 때문에, 경로 자체보다 먼저 “어느 파일에서 로드되었는가”가 중요합니다.


zsh 파일 읽는 순서를 모르면 같은 설정을 여러 곳에 넣게 된다

zsh는 모든 실행에서 .zshenv를 읽고, 로그인 셸에서는 .zprofile을 읽은 뒤 인터랙티브 셸에서 .zshrc를 읽습니다. 그래서 자주 쓰는 별칭이나 버전 관리 초기화는 .zshrc에, 로그인 환경에서 먼저 잡아야 할 PATH 성격의 설정은 .zprofile에 두는 편이 덜 꼬입니다. 반대로 .zshenv에 무거운 초기화나 출력이 들어가면 예기치 않은 오류가 생기기 쉽습니다.


읽는 순서(대표 흐름)
1) ~/.zshenv
2) ~/.zprofile   # 로그인 셸
3) ~/.zshrc      # 인터랙티브 셸
4) ~/.zlogin     # 로그인 셸

수정 전에 먼저 확인할 것

가장 먼저 할 일은 “어디에 무엇이 이미 들어 있는지”를 찾는 것입니다. PATH 문제는 새 줄을 추가하는 것보다, 기존 중복 라인을 지우는 쪽이 더 중요할 때가 많습니다. 특히 예전 bash 설정이 남아 있거나, 설치 가이드마다 다른 줄을 복사해 넣은 상태라면 같은 초기화가 두 번씩 실행되고 있을 가능성이 큽니다.


cp ~/.zshrc ~/.zshrc.bak 2>/dev/null
cp ~/.zprofile ~/.zprofile.bak 2>/dev/null
cp ~/.zshenv ~/.zshenv.bak 2>/dev/null

grep -nE 'brew shellenv|pyenv|nvm|PATH=' ~/.zshenv ~/.zprofile ~/.zshrc ~/.zlogin 2>/dev/null

먼저 지워볼 중복 패턴

brew shellenv.zprofile.zshrc에 동시에 있거나, eval "$(pyenv init - zsh)"와 수동 shims PATH 추가가 여러 파일에 흩어져 있으면 우선 정리 대상입니다. nvm도 예전 bash용 줄이 .bashrc에만 있고 현재 zsh에서는 비어 있는 경우가 흔합니다. 지금 실제로 쓰는 셸이 zsh라면 zsh 쪽 파일을 기준으로 먼저 정상화하는 편이 낫습니다.


.zshenv에 넣지 않는 편이 좋은 것

.zshenv는 모든 zsh 실행에서 읽히기 때문에 무거운 초기화, 자동 전환, 출력이 생기는 설정을 넣기 좋은 자리가 아닙니다. pyenv와 nvm 초기화를 이 파일에 몰아 넣으면 터미널뿐 아니라 여러 비대화형 실행까지 영향을 받아서 문제를 키우는 경우가 있습니다. PATH 충돌을 정리할 때 .zshenv는 비워 두거나 정말 기본 환경 변수만 남기는 편이 안전합니다.


가장 덜 꼬이는 권장 배치

정리 기준은 단순합니다. Homebrew는 먼저, pyenv와 nvm은 나중입니다. macOS에서 Homebrew 경로를 먼저 안정적으로 잡고, 그다음 인터랙티브 셸에서 pyenv와 nvm을 로드하면 충돌 지점을 많이 줄일 수 있습니다. 아래 예시는 가장 무난한 기본형입니다.


~/.zprofile 예시

# Homebrew: 로그인 셸에서 먼저 경로를 잡음
if [ -x /opt/homebrew/bin/brew ]; then
  eval "$(/opt/homebrew/bin/brew shellenv)"
elif [ -x /usr/local/bin/brew ]; then
  eval "$(/usr/local/bin/brew shellenv)"
fi

~/.zshrc 예시

# pyenv
export PYENV_ROOT="$HOME/.pyenv"
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
command -v pyenv >/dev/null 2>&1 && eval "$(pyenv init - zsh)"

# nvm
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"

이렇게 나누면 Homebrew가 먼저 정상 경로를 잡고, pyenv는 그 위에서 Python 관련 명령을 shims로 받으며, nvm은 인터랙티브 셸에서 Node 버전 전환을 맡게 됩니다. 중요한 점은 같은 줄을 다른 파일에 다시 넣지 않는 것입니다. 한 번 정했으면 같은 역할의 코드는 한 자리에서만 관리하는 편이 좋습니다.


로그인 셸이나 GUI 앱에서 pyenv 버전이 안 먹는 경우에는 .zprofile에 아래 한 줄만 추가로 테스트해 볼 수 있습니다. 이 방식은 pyenv 전체 셸 기능이 아니라 shims 쪽 반영이 필요한 상황에서 특히 유용합니다.


command -v pyenv >/dev/null 2>&1 && eval "$(pyenv init --path)"


zsh에서 설정 파일이 읽히는 순서와 Homebrew, pyenv, nvm PATH 정리 흐름을 단순하게 보여주는 보조이미지

zsh 시작 파일 순서와 PATH 정리 우선순위를 설명하는 보조 이미지


아직 꼬여 있다면 이 순서로 확인하면 된다

설정을 저장한 뒤에는 터미널을 완전히 새로 열거나 exec zsh로 다시 시작하는 편이 깔끔합니다. 그다음 PATH 순서와 실제 명령 해석 결과를 같이 봐야 합니다. 눈으로 파일만 보는 것보다 현재 셸이 무엇을 먼저 잡는지 확인하는 쪽이 훨씬 정확합니다.


exec zsh

print -l $path
type -a brew
type -a python python3 pip
type -a node npm
command -v nvm
pyenv version
nvm current

Python이 안 바뀌면 먼저 볼 것

pyenv global을 바꿨는데도 python이나 python3가 Homebrew 경로나 시스템 Python을 가리킨다면, 대부분은 shims가 PATH 앞쪽에 오지 않았거나 셸이 다시 로드되지 않은 경우입니다. 이럴 때는 수동으로 ~/.pyenv/shims를 여러 군데 추가하기보다, pyenv 초기화 줄을 한 번만 남기고 중복 PATH 수정을 지우는 쪽이 더 안정적입니다.


nvm이 안 보이면 먼저 볼 것

nvm은 실행 파일이 아니라 셸 함수라서 which nvm보다 command -v nvm으로 확인하는 편이 맞습니다. 설치는 됐는데 “command not found”가 뜬다면 .zshrc에 nvm 로드 줄이 실제로 들어 있는지, 저장 후 새 셸이 열렸는지부터 확인하면 됩니다. 예전 bash 설정만 남아 있고 zsh 쪽이 비어 있는 경우도 흔합니다.


Homebrew의 node와 nvm의 node를 같이 기본값으로 두지 않는 편이 낫다

Homebrew는 패키지 관리자 역할에 집중시키고, Node 버전 전환은 nvm 하나로 맡기는 편이 관리가 쉽습니다. 둘을 동시에 기본 node로 쓰기 시작하면 프로젝트마다 버전이 달라질 때 경로 해석이 자꾸 달라집니다. 반대로 Python 쪽도 pyenv를 쓴다면 Python 버전 선택은 pyenv 기준으로 통일하는 편이 덜 헷갈립니다.


VSCode 터미널에서만 증상이 다르게 보인다면 터미널 시작 셸과 PATH 표시 순서를 함께 점검하는 것이 빠릅니다. 같은 설정이어도 앱 안의 통합 터미널에서 읽는 환경이 달라 보일 수 있어서, 이런 경우는 VSCode 터미널 기본기 2026: zsh 설정 + 폰트/한글 깨짐/경로(PATH) 문제처럼 셸 시작 방식부터 같이 보는 편이 정리가 잘 됩니다.


정리하면 수정 순서는 이렇게 보면 된다

첫째. 현재 쓰는 zsh 파일에 무엇이 들어 있는지 찾고 중복 라인을 지웁니다. 둘째. Homebrew는 .zprofile에 두고 로그인 셸에서 먼저 경로를 안정화합니다. 셋째. pyenv와 nvm은 .zshrc에 모아서 인터랙티브 셸 기준으로 정리합니다. 넷째. 새 셸을 열고 type -a, command -v, print -l $path로 실제 해석 결과를 확인합니다.


결국 PATH 문제는 도구가 많아서 생긴다기보다, 같은 도구의 설정이 여러 파일에 흩어져서 생기는 경우가 많습니다. 파일 역할을 나눠서 한 번 정리해 두면 이후에는 Homebrew 업데이트, pyenv 버전 추가, nvm 버전 전환을 해도 훨씬 덜 흔들립니다.


참고자료(외부링크)


공식 문서
zsh 시작 파일 순서와 Homebrew·pyenv·nvm 기본 설정 확인

zsh가 어떤 파일을 어떤 순서로 읽는지, Homebrew 경로를 어디에 두는지, pyenv와 nvm 초기화를 어떤 형태로 넣는지 공식 설명을 한 번에 다시 확인할 수 있습니다.

→ zsh startup files 설명 보기

→ Homebrew shellenv와 zsh 설정 확인하기

→ pyenv 기본 초기화 예시 다시 보기

→ nvm zshrc 로드 예시 다시 보기


설치 자체가 꼬인 상태라면 본문 설정만 손보는 것보다, 먼저 설치 기준 글을 다시 보는 편이 더 빠를 때도 있습니다.



함께 보면 좋은 글
Homebrew 경로부터 다시 점검해야 할 때
brew 자체가 안 잡히거나 권한 문제부터 섞여 있다면 Homebrew 설치 상태를 먼저 정리하는 편이 빠릅니다.
Homebrew 2026 설치 가이드: brew command not found/권한 오류까지 한 번에 해결(맥북)

함께 보면 좋은 글
pyenv를 계속 쓸지 다른 Python 관리 방식을 볼지 고민될 때
PATH 정리를 했는데도 Python 환경이 자꾸 섞인다면 pyenv, conda, uv 중 어떤 조합이 맞는지부터 다시 보는 편이 도움이 됩니다.
Python 개발환경 2026: pyenv vs conda vs uv 비교 + 초보 추천 조합(맥/윈도우/VSCode)

자주 묻는 질문

Q1. Homebrew, pyenv, nvm 설정을 전부 .zshrc에 넣어도 되나요?

전부 .zshrc에 몰아 넣어도 돌아갈 수는 있지만, macOS에서는 Homebrew 경로처럼 로그인 셸에서 먼저 잡아두면 좋은 설정이 있습니다. 그래서 .zprofile에는 Homebrew처럼 기본 경로 성격의 설정을 두고, .zshrc에는 pyenv·nvm처럼 인터랙티브 셸 초기화를 두는 쪽이 더 안정적입니다.

Q2. pyenv global을 바꿨는데 python 버전이 그대로면 무엇부터 봐야 하나요?

가장 먼저 type -a python python3print -l $path를 확인하는 편이 좋습니다. pyenv shims가 PATH 앞쪽에 오지 않았거나, 셸을 다시 시작하지 않아 예전 경로를 계속 쓰고 있는 경우가 많습니다. 이때는 shims 경로를 여기저기 수동 추가하기보다 pyenv 초기화 줄을 한 군데로 정리하는 쪽이 더 깔끔합니다.

Q3. nvm 설치 후 which nvm이 안 나오는데 설치가 실패한 건가요?

꼭 그렇지는 않습니다. nvm은 실행 파일이 아니라 셸 함수로 로드되는 구조라서 which nvm보다 command -v nvm으로 확인하는 편이 맞습니다. .zshrc에 nvm 로드 줄이 들어 있는지 확인하고, 파일 저장 후 새 터미널을 열거나 exec zsh로 다시 읽히게 한 뒤 확인해 보세요.

Q4. Homebrew로 설치한 node와 nvm을 같이 유지해도 괜찮나요?

같이 존재할 수는 있지만, 기본 node 경로를 어느 쪽이 맡을지는 하나로 정하는 편이 좋습니다. 프로젝트별 버전 전환이 필요하면 nvm을 기준으로 두고, Homebrew는 nvm 자체나 다른 패키지 설치 용도로 쓰는 편이 관리가 쉽습니다. 두 방식을 동시에 기본값으로 끌고 가면 PATH 문제를 다시 만나기 쉽습니다.


터미널 PATH 문제는 새 도구를 더 설치하기보다, 이미 들어 있는 초기화 줄을 역할별로 나누는 것만으로도 풀리는 경우가 많습니다. 셸 파일을 한 번 정리해 두면 이후 설치와 버전 전환도 훨씬 단순해집니다.