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

Shell Configuration Files

~13 min · zshrc, zprofile, zshenv, bashrc

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

Why are there so many of them?

zsh reads up to four config files at startup. Each has a different purpose. Putting the right line in the wrong file is the most common "my env doesn't load" bug.

The four zsh files

  • ~/.zshenv — runs for every zsh invocation, including non-interactive scripts. Use sparingly.
  • ~/.zprofile — login shells only (the first shell of a session). Set $PATH here. Homebrew shellenv lives here.
  • ~/.zshrc — interactive shells. Aliases, prompts, plugins, completion. Most of your config goes here.
  • ~/.zlogin — login shells, after .zshrc. Rarely used.

The bash equivalents

  • ~/.bash_profile — login shells.
  • ~/.bashrc — interactive non-login shells.
  • Old hack: source one from the other so you only edit .bashrc.

Login vs interactive (preview)

Login shell = the first shell of a session; interactive means you can type at a prompt. A macOS Terminal window is commonly both, while an SSH command may start a different shell shape. Scheduled jobs are a separate boundary: cron and launchd do not read zsh startup files for you. Next lesson covers the table.

Where to put what

  • PATH and locale for a login zsh → .zprofile. Scheduled jobs do not inherit it automatically; declare their environment in the job or a controlled wrapper.
  • Aliases, functions, prompt → .zshrc.
  • Variables you want every script to see → .zshenv (rare).

Reload after editing

source ~/.zshrc or exec zsh reloads. The second is cleaner — it replaces the current shell with a fresh one and preserves your terminal window.

Startup files have different frequency and side effects

.zshenv can run for non-interactive zsh, so output, slow commands, or prompt setup there can break scripts. Put login and interactive work in narrower files and keep universal startup fast and silent.

source and a new shell are different reloads

source ~/.zshrc reapplies configuration on top of current state and can duplicate PATH entries or hooks. Even exec zsh may not reproduce the original login context. Validate with the kind of fresh session the changed file actually owns.

Code

Verify the load order·bash
# Add a print to each file so you can see when each runs
echo 'echo ".zshenv loaded"'   >> ~/.zshenv
echo 'echo ".zprofile loaded"' >> ~/.zprofile
echo 'echo ".zshrc loaded"'    >> ~/.zshrc
# Open a new terminal — note the order
# Then remove these lines once you've seen them
Reload without closing the terminal·bash
exec zsh           # cleanest
source ~/.zshrc    # also fine for interactive only
# After editing PATH / .zprofile, prefer exec zsh

External links

Exercise

Add a temporary echo marker to each of .zshenv, .zprofile, and .zshrc. Open a new Terminal window and record the order, then run zsh -c 'echo noninteractive-zsh' to observe a non-interactive zsh. If you also inspect bash, add a separate temporary marker to .bashrc and run bash -c 'echo noninteractive-bash'; do not use a bash result to infer zsh startup order. Remove every marker when done.

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.