Skip to content

fzf & zoxide — Fuzzy Finder & Smart Directory Jump

DodaTech Updated 2026-06-24 9 min read

In this tutorial, you'll learn about fzf & zoxide. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

fzf is a general-purpose fuzzy finder that lets you search and select from any list — files, processes, commands, Git branches — with instant filtering. zoxide learns your directory navigation patterns and replaces cd with a jump command that learns your habits.

What You'll Learn

How to use fzf for interactive file searching, command history, Process killing, and Git operations. How zoxide learns your directory patterns and lets you jump across the filesystem with a few keystrokes. How to combine both tools for a seamless terminal workflow.

Why fzf and zoxide Matter

Navaging the terminal is a core developer activity — finding files, switching directories, recalling commands. Without fzf and zoxide, you type full paths, scroll through history, or use find and grep. With fzf, you press Ctrl+T and instantly filter files by partial name. With zoxide, z proj takes you to /home/user/work/project/src because it knows that is where you go most. DodaZIP's CI team uses fzf for interactive log inspection — journalctl -u build | fzf — filtering thousands of log lines to find relevant entries in seconds.

Learning Path

flowchart LR
  A[bat & delta] --> B[fzf & zoxide
You are here] B --> C[Starship Prompt] B --> D[Ripgrep & fd] style B fill:#f90,color:#fff

fzf — Fuzzy Finder

Installation

# macOS
brew install fzf

# Ubuntu/Debian
sudo apt install fzf

# Fedora
sudo dnf install fzf

# Arch
sudo pacman -S fzf

# Install key bindings and completion
$(brew --prefix)/opt/fzf/install
# Or for Linux:
/usr/share/doc/fzf/examples/install --key-bindings --completion --no-update-rc

Key Bindings

After installing key bindings, three shortcuts transform your shell:

Binding Action
Ctrl+T Paste selected file/directory path into command
Ctrl+R Fuzzy-search command history
Alt+C cd into selected directory
# Examples using key bindings:
vim **<TAB>          # Tab completion triggers fzf for files
kill -9 **<TAB>      # fzf lists running processes
ssh **<TAB>          # fzf lists SSH hosts from known_hosts
cd **<TAB>           # fzf lists directories (if zoxide integration)

Basic Usage

# Pipe any list to fzf
find . | fzf
ps aux | fzf
git branch | fzf
history | fzf

# Select multiple items
find . | fzf -m

# Execute command on selection
fzf --bind 'enter:execute(nvim {})'

# Preview file content
fzf --preview 'cat {}'

# Preview with syntax highlighting
fzf --preview 'bat --color=always {}'

# Preview directory contents
fzf --preview 'ls -la {}' --preview-window=right:60%

Advanced fzf

# Search with fzf and open in editor
nvim $(fzf --preview 'bat --color=always {}')

# Kill a process interactively
kill -9 $(ps aux | fzf | awk '{print $2}')

# Git checkout branch interactively
git checkout $(git branch --all | fzf | tr -d ' *')

# Search code with rg and preview with bat
rg -l "TODO" | fzf --preview 'bat --color=always {}'

# SSH to a host
ssh $(grep -E "^Host " ~/.ssh/config | awk '{print $2}' | fzf)

# Docker operations
docker stop $(docker ps | fzf | awk '{print $1}')
docker logs $(docker ps | fzf | awk '{print $1}') -f

Custom FZF Configuration

# ~/.zshrc or ~/.bashrc
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow'
export FZF_DEFAULT_OPTS='--height 40% --layout=reverse --border'
export FZF_CTRL_T_COMMAND='fd --type f --hidden'
export FZF_CTRL_T_OPTS='--preview "bat --color=always {}"'
export FZF_ALT_C_COMMAND='fd --type d --hidden'
export FZF_ALT_C_OPTS='--preview "ls -la {}"'

# Use ripgrep for CTRL-R (faster than reading .bash_history)
export FZF_CTRL_R_OPTS='--sort --preview "echo {}" --preview-window down:3:wrap'

fzf with tmux

# Open fzf in a tmux popup
fzf --tmux

# With custom size
fzf --tmux 80%
fzf --tmux 80%,40%   # 80% width, 40% height

Git Integration Script

# ~/bin/git-fzf.sh — interactive Git operations
#!/bin/bash

case "$1" in
  checkout)
    git branch --all | fzf | tr -d ' *' | xargs git checkout
    ;;
  log)
    git log --oneline --graph --all | fzf --preview 'echo {} | cut -d" " -f1 | xargs git show' | cut -d" " -f1 | xargs git show
    ;;
  diff)
    git log --oneline | fzf -m | cut -d" " -f1 | xargs git diff
    ;;
  stash)
    git stash list | fzf | cut -d: -f1 | xargs git stash apply
    ;;
esac

zoxide — Smarter Directory Jump

Installation

# macOS
brew install zoxide

# Ubuntu/Debian
sudo apt install zoxide

# Fedora
sudo dnf install zoxide

# Arch
sudo pacman -S zoxide

# With curl
curl -sS https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | bash

Shell Integration

# Add to ~/.zshrc or ~/.bashrc:
eval "$(zoxide init zsh)"    # for zsh
eval "$(zoxide init bash)"   # for bash
eval "$(zoxide init fish)"   # for fish

Basic Usage

# Replace cd with z
z projects
z work/src

# Jump to the most recent match
z projects

# Interactive selection with fzf
zi

# List all directories with their rankings
zoxide query -l

# Jump to a subdirectory
z projects/src/utils

# Add a directory to the database manually
zoxide add /path/to/directory

zoxide in Action

# Instead of:
cd ~/work/project/src/components/

# Just type:
z comp

# zoxide finds the best match based on frequency and recency

# Multiple matches — zoxide shows the top choice:
# If multiple directories match "comp":
# 1. ~/work/project/src/components (visited 45 times)
# 2. ~/work/other-project/comp (visited 3 times)
# z picks the first one

# Use `zi` for interactive selection when unsure
zi comp
# Opens fzf with matching directories ranked by score

Advanced zoxide

# Exact match (no fuzzy)
z '^/home/user/projects$'

# Best match for subdirectory
z 'src'  # matches ~/work/project/src

# Remove a directory from database
zoxide remove /old/path

# Purge directories that no longer exist
zoxide query -l | while read d; do [ -d "$d" ] || zoxide remove "$d"; done

# Use with cd for fallback
unalias cd 2>/dev/null
cd() {
    if [ "$#" -eq 0 ]; then
        builtin cd ~
    elif [ "$#" -eq 1 ] && [ -d "$1" ]; then
        builtin cd "$1"
    elif [ "$#" -eq 1 ]; then
        z "$1"
    else
        builtin cd "$@"
    fi
}

Integration with fzf

# zoxide + fzf: interactive directory jumping
# Already available as `zi` after zoxide init

# Or manually:
zoxide query -l | fzf --preview 'ls -la {}'

# Combined with fd for file search:
cd $(zoxide query -l | fzf)
vim $(fd -t f | fzf)

Real-World Workflow

# Morning routine with fzf + zoxide:
# 1. Jump to project
z myproject

# 2. Find the file you need
nvim $(fzf --preview 'bat --color=always {}')

# 3. Search for the function you need
rg "def process_" -l | fzf

# 4. Git operations with fzf
git log --oneline | fzf | cut -d" " -f1 | xargs git show

# 5. Jump to logs directory
z logs
tail -f $(fzf)

# 6. Find that command from yesterday
Ctrl+R -> type "deploy" -> fuzzy filter -> Enter

Common Errors

1. fzf Shows "command not found" After Installation

The fzf binary may not be in PATH. On Ubuntu with apt, fzf is in /usr/bin/fzf. Verify: which fzf. Re-run the install script for key bindings.

2. zoxide Scores Not Accurate

zoxide ranks by frequency and recency. If your most-visited directory is not ranking first, the algorithm may need more data. Use zoxide query -l to see scores.

3. Ctrl+T Does Nothing

The key bindings script was not sourced. Add eval "$(fzf --zsh)" or eval "$(fzf --bash)" to your shell config and reload.

4. zoxide "zi" Not Working

The interactive mode requires fzf to be installed. Ensure both fzf and zoxide are installed, and eval "$(zoxide init zsh)" is in your config.

5. fzf Preview Shows Nothing

The preview command may not be found. Use full paths or ensure the tool (bat, cat, ls) is installed. Check with fzf --preview 'cat {}'.

6. zoxide Database Out of Sync

If you move or rename directories, zoxide still has the old paths. Remove them: zoxide remove /old/path.

7. fzf Performance Is Slow on Large Repos

If FZF_DEFAULT_COMMAND= uses find on a repo with node_modules, fzf will be slow. Use fd instead of find: export FZF_DEFAULT_COMMAND='fd --type f'.

Practice Questions

1. What are the three default fzf key bindings? Ctrl+T (files), Ctrl+R (history), Alt+C (directories).

2. How does zoxide decide which directory to jump to? It uses a frecency algorithm — a combination of frequency (how often you visit) and recency (when you last visited).

3. How do you make fzf preview file contents while searching? Use --preview 'bat --color=always {}' or --preview 'cat {}'.

4. What is the difference between z and zi in zoxide? z jumps directly to the best match. zi opens an interactive fzf selection of all matches.

5. How do you use fzf to kill a Process interactively? kill -9 $(ps aux | fzf | awk '{print $2}') — fzf selects the Process, awk extracts the PID.

Challenge: Create a shell function called nav that: (1) uses zoxide to list the top 20 directories, (2) displays them in fzf with directory contents in the preview pane, (3) on selection, changes to that directory, (4) if no directories match, uses fd to search the filesystem. Also create a gf (git find) function that uses fzf to interactively search and checkout branches, view commits, and apply stashes.

Do fzf and zoxide work together?

Yes — zoxide's zi command already uses fzf internally. You can also pipe zoxide output to fzf for custom workflows: zoxide query -l | fzf.

Can I use fzf in scripts?

Yes — fzf is pipe-friendly. Use fzf < /tmp/list.txt or echo -e "a\nb\nc" | fzf. The selected item is printed to stdout.

Does zoxide work across terminal sessions?

Yes — the database is stored in ~/.local/share/zoxide/db.zo and persists across sessions, reboots, and machines (if synced).

How do I clear my zoxide database?

zoxide init --no-cmd and remove ~/.local/share/zoxide/. The database rebuilds as you navigate.

What happens if multiple directories match equally with zoxide?

zoxide uses a tiebreaker based on the last access time — the most recently visited directory wins.

What's Next

Starship Prompt — Custom Shell Prompt
ripgrep & fd — Modern File Search
Zsh & Oh My Zsh — Shell Enhancement

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Updated 2026-06-24.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro