Skip to content
C.W.K.
Stream
Lesson 05 of 10 · published

PATH Management

~10 min · path, homebrew, ordering

Level 0Window Tourist
0 XP0/95 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

The list that decides every command

$PATH is a colon-separated list of directories. The shell walks it left-to-right looking for executables. Everything you install adds to it; managing the order is what keeps multiple Pythons / Nodes / brews from fighting.

Append vs prepend

  • export PATH="$PATH:/new/dir" — append. New tool used only if a system one with the same name doesn't exist.
  • export PATH="/new/dir:$PATH" — prepend. New tool wins. What you want for Homebrew, pyenv, mise, etc.

The Apple Silicon Homebrew dance

On Apple Silicon, Homebrew lives at /opt/homebrew/bin. Add this to ~/.zprofile:

eval "$(/opt/homebrew/bin/brew shellenv)"

That one line sets PATH, MANPATH, INFOPATH, and a few brew vars in one atomic step. The official install script writes it for you on a fresh Mac.

Deduplicate

Sourcing the same file twice can repeat entries. zsh has a typeset -U path declaration that auto-deduplicates. After typeset -U path, every PATH addition is unique by string.

Inspect

echo $PATH | tr ':' '\n'
echo $PATH | tr ':' '\n' | sort | uniq -d  # any duplicates?
type python3       # which one wins?

Per-project PATH overrides

direnv (next-but-one lesson) lets a project-local .envrc insert its own bin dir at the front of PATH for that directory only. Combined with mise (modern-tools), each project can ship its toolchain without polluting the global env.

PATH is a search policy, not just a string

An early directory can shadow a system binary, and some implementations treat an empty entry as the current directory. After editing PATH, inspect the winner and alternatives with command -v and type -a.

Give one layer ownership of a project's runtime

If Conda, mise, pyenv, and Homebrew all rewrite PATH, activation order chooses the interpreter. Declare the manager owned by the repository and service, and keep other layers outside that boundary.

Code

Best practice .zprofile snippet·zsh
# Apple Silicon Homebrew
eval "$(/opt/homebrew/bin/brew shellenv)"
# Auto-dedupe PATH and FPATH
typeset -U path fpath
# Per-user bin
path=("$HOME/.local/bin" "$HOME/bin" $path)

External links

Exercise

echo $PATH | tr ':' '\n' and read it. echo $PATH | tr ':' '\n' | sort | uniq -d to find duplicates. Add typeset -U path to .zprofile, open new terminal, run the dup check again.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.