Installing zoxide is easy. Getting from “the binary exists” to “the z command works every time I open a terminal” is where people tend to lose ten minutes.
The reason is simple: zoxide has two layers. The executable stores and queries directory history; a small piece of shell code defines z, zi, and the hook that records where you go. A package manager installs the first layer. zoxide init supplies the second.
If the tool is new to you, this short explanation of what zoxide is covers the mental model. The rest of this post is the setup I use to get a clean, testable installation.
Disclosure: I maintain zoxide.org as an independent guide site. It is not the official zoxide project. Commands in this post were checked against the official zoxide repository.
1. Install the binary
Pick one method for your platform. Do not install the same executable with three package managers; that makes later upgrades and PATH debugging needlessly confusing.
Linux and WSL:
curl -sSfL https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | sh
macOS with Homebrew:
brew install zoxide
Windows with WinGet:
winget install ajeetdsouza.zoxide
Any platform with a working Rust toolchain:
cargo install zoxide --locked
There are more distribution-specific options in this install zoxide guide. Whichever route you choose, verify the executable before touching your shell config:
zoxide --version
If that command fails, stop here. This is an installation or PATH problem, not a shell-initialization problem.
2. Initialize the shell
Add exactly one matching line near the end of your shell configuration.
Bash (~/.bashrc):
eval "$(zoxide init bash)"
Zsh (~/.zshrc):
eval "$(zoxide init zsh)"
Fish (~/.config/fish/config.fish):
zoxide init fish | source
PowerShell ($PROFILE):
Invoke-Expression (& { (zoxide init powershell | Out-String) })
Nushell uses two files. Generate the integration from the environment file:
zoxide init nushell | save -f ~/.zoxide.nu
Then load it from the config file:
source ~/.zoxide.nu
Restart the terminal after saving the file. Sourcing the file works too, but a fresh process is a better test: it proves the setup survives a normal shell launch.
3. Verify all three layers
A reliable diagnosis checks the executable, generated shell function, and database separately.
Check the executable
command -v zoxide
zoxide --version
PowerShell equivalent:
Get-Command zoxide
zoxide --version
Check the generated command
For Bash and Zsh:
type z
type zi
For Fish:
type -a z
type -a zi
You should see a function rather than a second unrelated executable.
Check the database
Visit a few directories normally, then inspect what zoxide knows:
zoxide query --list --score
If the list stays empty after normal navigation, the hook is not loading. Look for an early return in the shell config, competing cd wrappers, or an init line placed before a framework that overwrites it.
4. Use the small command set that matters
You do not need to memorize much:
z project # Jump to the best match
z client api # Match multiple keywords
z - # Return to the previous directory
zi project # Choose interactively with fzf
The underlying database commands are useful when a match looks wrong:
zoxide query --list --score project
zoxide add ~/src/important-project
zoxide remove ~/src/old-project
The extended zoxide commands reference covers import, query flags, environment variables, and database maintenance. For daily use, the six commands above are usually enough.
5. Fix the common failure modes
zoxide works, but z is not found
The binary is installed; the shell integration is missing or loaded from the wrong file. Confirm which shell is actually running:
ps -p $$ -o comm=
Then put the matching init line in the startup file that interactive sessions read.
zi says it cannot find fzf
zi uses fzf for interactive selection. Install fzf, verify it is on PATH, and restart the shell:
fzf --version
Plain z keyword works without the interactive picker.
A keyword opens the wrong directory
Inspect the candidates before changing anything:
zoxide query --list --score keyword
Zoxide ranks by frequency and recency. Visiting the intended directory, or explicitly adding it, raises its score. Remove a stale entry only when you are sure it is no longer useful.
Aliasing cd causes recursion or odd behavior
Do not write alias cd=z. Let zoxide generate a safe replacement:
eval "$(zoxide init zsh --cmd cd)"
Use the equivalent command for your shell. If the behavior is still strange, return to the default z command first and rule out other cd wrappers.
A clean setup is observable
The most useful habit is to test one layer at a time:
-
zoxide --versionproves installation and PATH. -
type zproves shell initialization. -
zoxide query --list --scoreproves the hook is recording directories.
Once those three checks pass, zoxide stops feeling magical and becomes a small, predictable terminal tool—which is exactly what a navigation utility should be.
Top comments (0)