.zprofile, .zshrc, .zenv, OMG! What Do I Put Where?!

z-shell has quite a bunch of startup and shutdown files. So sometimes it gets difficult to decide what kind of functions, aliases, and operations to define in which of those files.

Introduction

Z-shell has quite a bunch of startup and shutdown files. So sometimes it gets difficult to decide what kind of functions, aliases, and operations to define in which of those files.

Here is the complete list of files:

$ZDOTDIR/.zshenv
$ZDOTDIR/.zprofile
$ZDOTDIR/.zshrc
$ZDOTDIR/.zlogin
$ZDOTDIR/.zlogout
zsh startup files.

In this article, we’ll cover what those files are for, when, and how to use them.

What is ~/.zprofile

~/.zprofile is one of the zsh startup and shutdown files. It is read at login. There’s also its cousin, ~/.zshrc, which is read when interactive.

Login and Interactive Shells

But what is login, and what is interactive?

Or—to ask differently—what is a login shell and what is an interactive non-login shell?

A login shell is a shell where you log in. You can recognize a login shell from a ps -f listing. For example, when I call ps -f after opening a Mac terminal, I get the following:

volkan@iMac ~ % ps -f
  UID   PID  PPID   C STIME   TTY           TIME CMD
  501 22250 22249   0  6:47PM ttys000    0:00.18 -zsh

An interactive non-login shell is typically a shell environment that you can read from and write to (i.e., your typical terminal session). An interactive non-login shell can be invoked from the login shell, such as when you type zsh and press enter in the command prompt. Or, it can be invoked when you open a new terminal tab.

What Goes to ~/.zprofile and What Goes to ~/.zshrc?

Since ~/.zprofile is loaded only once at login time, it’s best to put things that are loaded only once and can be inherited by subshells. An excellent example of this is environment variables.

On the other hand, ~/.zshrc is typically reserved for things that are not inheritable by subshells, such as aliases and functions, custom prompts, history customizations, and so on.

In addition, put the commands that should run every time you launch a new shell in the .zshrc file, too.

What About .zshenv?

For Z-Shell, another good place to put environment variables is the ~/.zshenv file. The ~/.zshenv file is always loaded. See the remainder of the article for details. That said, I, personally, prefer putting my environment variables into ~/.zprofile.

zsh Startup and Shutdown Files

.zprofile and .zshrc are the two main startup files that you’ll 99% be dealing with. Yet, other files have their uses too. Let’s see all together.

You can refer to the official reference if you like. I will just add some notes and comments that you may not find in the official docs, to clarfiy things a little, if you will.

.zprofile

.zlogin and .zprofile do the same thing. They set the environment for login shells. The only difference is they just get loaded at different times (see below). I would use .zprofile at all times for consistence.

.zshrc

.zshrc sets the environment for interactive shells. .zshrc gets loaded after .zprofile. It is a place where you “set and forget” things.

Since it’s loaded after .zprofile, in interactive shells, it will override anything you set in .zprofile. Like the $PATH variable. It’s a good place to define aliases and functions that you would like to have both in login and interactive shells (see the sidenote below).

.zprofile Quirks

Apple terminal initially opens both a login and an interactive shell even though you don't authenticate (i.e., enter login credentials). That’s why .zshrc will always be loaded. However, after the first terminal session, any subsequent shells that are opened are only interactive; thus .zprofile will not be loaded.

You can test this out by putting an alias or setting a variable in .zprofile, then opening Terminal and seeing if that variable/alias exists. Then open another shell (type zsh); that variable won't be accessible anymore.

.zshenv

This is read first and read every time, regardless of the shell being login, interactive, or none.

This is the recommended place to set environment variables, though I still prefer to set my environment variables in .zprofile

Why would you need it? Because, for example, if you have a script that gets called by launchd, it will run under non-interactive non-login shell, so neither .zshrc nor .zprofile will get loaded.

I’ve never needed to use this file so far, but it’s there if you need it, and there is nothing wrong with using it to define envinronment variables.

.zlogout

This file is read when you log out of a session. Useful for cleaning things up.

File Load Order

Here’s the order these profile files are processed, without getting into too much detail:

.zshenv.zprofile.zshrc.zlogin.zlogout

Conclusion

That was an overview of Z-Shell startup and shutdown files. If you are a bash user, bash has a a similar set up startup files too.

Aside

For the sake of completeness, this knowledge base contains startup and termination files used by various unix systems.

I hope this article clarifies what all these Z-Shell startup files are, and how to use them in the most canonical way.

Until the next article… may the source be with you 🦄.

 \
 \\,
  \\\,^,.,,.                     Zero to Hero
  ,;7~((\))`;;,,               <zerotohero.dev>
  ,(@') ;)`))\;;',    stay up to date, be curious: learn
   )  . ),((  ))\;,
  /;`,,/7),)) )) )\,,
 (& )`   (,((,((;( ))\,

Subscribe to Zero to Hero

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe