The zsh directory stack isn’t just a place to stash directories; it’s a dynamic, ordered list that fundamentally changes how you navigate your filesystem, allowing for instant jumps between frequently used locations.
Let’s see it in action. Imagine you’re deep in a project.
cd ~/projects/my-awesome-app/src/utils
pwd
# Output: /Users/youruser/projects/my-awesome-app/src/utils
pushd ../../tests
# Output:
# 2 ~/projects/my-awesome-app/src/utils
# 1 ~/projects/my-awesome-app/tests
# Output of pwd after pushd: /Users/youruser/projects/my-awesome-app/tests
pushd ../../docs
# Output:
# 3 ~/projects/my-awesome-app/tests
# 2 ~/projects/my-awesome-app/src/utils
# 1 ~/projects/my-awesome-app/docs
# Output of pwd after pushd: /Users/youruser/projects/my-awesome-app/docs
Here, pushd doesn’t just change your directory; it adds the new directory to the top of a conceptual stack and displays the current stack. The directory you were in is now one level down. The pwd command now shows the latest directory you pushded into.
Now, to jump back to where you were:
popd
# Output:
# 2 ~/projects/my-awesome-app/src/utils
# 1 ~/projects/my-awesome-app/tests
# Output of pwd after popd: /Users/my-awesome-app/src/utils
popd
# Output:
# 1 ~/projects/my-awesome-app/tests
# Output of pwd after popd: /Users/my-awesome-app/tests
popd removes the top directory from the stack and immediately cds you to the directory that is now at the top. It’s like unwinding your navigation history.
The dirs command is your window into this stack.
dirs
# Output: ~/projects/my-awesome-app/tests ~~/projects/my-awesome-app/src/utils
dirs -v
# Output:
# 1 ~/projects/my-awesome-app/tests
# 2 ~/projects/my-awesome-app/src/utils
dirs alone shows the current stack, with the top of the stack appearing first. dirs -v provides a numbered, verbose output, clearly indicating the order. The numbers correspond to the positions in the stack.
The fundamental problem the directory stack solves is efficient management of multiple working directories. Instead of complex aliases or remembering long cd paths, you can pushd directories onto the stack as you enter them, and then popd or use dirs with a number to instantly switch back. This is invaluable when working on inter-dependent components, comparing files in different locations, or simply managing a complex project structure.
Internally, zsh (and bash, though with slightly different syntax for some operations) maintains a list of directory paths. pushd appends a new path to this list and updates your current working directory. popd removes the most recently added path and changes your current working directory to the one that is now at the top of the list. The dirs command simply displays the contents of this internal list.
You can manipulate the stack in more sophisticated ways. For instance, pushd +N will rotate the stack so that the Nth directory (1-indexed) becomes the top of the stack.
# Let's re-populate the stack for demonstration
pushd ~/projects/my-awesome-app/src/utils
pushd ../../tests
pushd ../../docs
# Current stack: docs, tests, utils
dirs -v
# Output:
# 1 ~/projects/my-awesome-app/docs
# 2 ~/projects/my-awesome-app/tests
# 3 ~/projects/my-awesome-app/src/utils
# Rotate the stack to bring tests to the top
pushd +2
# Output:
# 1 ~/projects/my-awesome-app/tests
# 2 ~/projects/my-awesome-app/docs
# 3 ~/projects/my-awesome-app/src/utils
# Output of pwd after pushd +2: /Users/youruser/projects/my-awesome-app/tests
# Rotate again to bring utils to the top
pushd +3
# Output:
# 1 ~/projects/my-awesome-app/src/utils
# 2 ~/projects/my-awesome-app/tests
# 3 ~/projects/my-awesome-app/docs
# Output of pwd after pushd +3: /Users/youruser/projects/my-awesome-app/src/utils
Here, pushd +2 took the directory at index 2 (~/projects/my-awesome-app/tests) and moved it to index 1, shifting the previous index 1 (~/projects/my-awesome-app/docs) down to index 2. The pwd command reflects this change. This rotation capability is incredibly powerful for quickly surfacing a specific directory without having to popd through several others.
A common point of confusion is how pushd handles existing directories on the stack. By default, pushd will add the directory even if it’s already present, creating duplicates. However, you can control this behavior. If you want to move an existing directory to the top of the stack instead of duplicating it, you can use pushd -n <directory>. This option removes the directory from its current position on the stack before pushing it to the top.
# Let's assume the stack is: docs, tests, utils
dirs -v
# Output:
# 1 ~/projects/my-awesome-app/docs
# 2 ~/projects/my-awesome-app/tests
# 3 ~/projects/my-awesome-app/src/utils
# Now, let's push 'tests' again, but using -n
pushd -n ~/projects/my-awesome-app/tests
# Output:
# 1 ~/projects/my-awesome-app/tests
# 2 ~/projects/my-awesome-app/docs
# 3 ~/projects/my-awesome-app/src/utils
# Output of pwd after pushd -n: /Users/youruser/projects/my-awesome-app/tests
Notice how tests moved from position 2 to position 1, and docs (which was at position 1) shifted down to position 2. The src/utils directory remained at the bottom. This prevents the stack from growing unnecessarily large with repeated visits to the same few directories.
Beyond simple navigation, the directory stack can be integrated into scripts or used for more advanced shell customization. For example, you could write a script that pushes a set of related project directories onto the stack, performs some operations, and then cleans them up with popd.
The next step in mastering zsh navigation often involves understanding how to use shell variables and functions to automate complex directory stack manipulations.