We're all familiar with using the cd command to jump around directories. Normally you need to know and type either an absolute path or a relative directory name when using cd, except for common shortcuts like:

> cd
/Users/kai

> cd ./code
/Users/kai/code

> cd ..
/Users/kai

> cd -
/Users/kai/code

In the above examples, we jumped $HOME (aka ~) by providing no arguments, then into an adjacent directory, into the parent directory, and back into the last directory, respectively. What I've seen most people do in practice is either manually type most of the path/directory, and then rely on tab completion to cycle through and finish, or they create aliases to use a single command as a shortcut to jump to their favorite directory:

> alias c="cd ~/code"

> c
/Users/kai/code

These all work, but if you're like me, you have a hundred directories worth of projects that you navigate in and out of.

CDPATH

CDPATH works similar to PATH in that you provide a comma-delimited list of directories that become the search path for the cd command. Let's look at a practical example to understand the benefits. For this example, assume I keep my projects organized in /Users/kai/code:

~/code
โฏ tree
.
โ”œโ”€โ”€ alpha
โ”œโ”€โ”€ beta
โ”œโ”€โ”€ charlie
โ”œโ”€โ”€ delta
โ”œโ”€โ”€ echo
โ”œโ”€โ”€ foxtrot
โ”œโ”€โ”€ golf
โ””โ”€โ”€ hotel

9 directories, 0 files

I can use CDPATH to set ~/code as a search path for cd:

export CDPATH=~/code

With this set, I can now type cd golf, from anywhere, and cd will utilize the search path to look for matching subdirectory names in each of the top-level directories that I provided to CDPATH.

Gotcha

In almost all cases, you will want the first directory in your CDPATH to be the current directory (aka .) so that you can continue to cd into relative directories:

export CDPATH=.:~/code

Now, if I have a subdirectory named golf in my current working directory, I will cd into the relative path, ./golf, rather than /Users/kai/code/golf. But what if I preferred to go to the latter? The next section has the answer.

Zoxide (Recommended)

Now that you have intuition into how search paths work, I trust that you can fix PATH issues yourself. Also, you don't actually need to use CDPATH directly because there is a more productive solution.

Zoxide provides the same jumpability benefit as CDPATH and adds quality of life improvements such as completions, duplicate directory name resolution, and automatic directory tracking so that you don't ever need to manage any environment variables yourself.

Install zoxide and its dependency fzf, then add the initialization script to your shell config and reload your shell:

> brew install zoxide fzf
...
๐Ÿบ  /opt/homebrew/Cellar/zoxide/0.9.8: 18 files, 1MB
...
๐Ÿบ  /opt/homebrew/Cellar/fzf/0.65.1: 19 files, 4.5MB
...

> echo 'eval "$(zoxide init zsh)"' >> ~/.zshrc

> exec zsh

Now, from this point forward, use z instead of cd. Zoxide will remember where to jump around to, so that you can recall later even faster. Example:

> z golf
zoxide: no match found

> z ~/code/golf
/Users/kai/code/golf

> z
/Users/kai

> z golf
/Users/kai/code/golf

Since installing Zoxide, I haven't jumped to ~/code/golf before, so using z golf found no matches. After I z into the directory myself, Zoxide knows where I've been, enabling me to jump back from anywhere via z golf, or even with a partial word match like z go. Eventually using something really short like z go can become ambiguous once you visit any other directories that start with or contain go. When path matches become similar, Space+Tab to resolve.

Here's a short animated demo, that I lifted directly from the official Zoxide GitHub repo.

Relevant Music

Only one song makes sense here. ๐Ÿ˜