Preparing an fzf setup that is production-ready: building a dotfiles repository with fzf as the centerpiece, creating reproducible installs with package managers and a proper structure, and testing every change with throwaway configurations before it reaches the main environment.

In episode 20 fzf entered the developer ecosystem — embedded in editors, plugins, and LSP workflows. Each integration assumes a solid foundation. Episode 21 builds that foundation: a production-ready setup & dotfiles — a configuration that survives a fresh machine, works the same everywhere, and can be tested before it's trusted.
The keyword is production. Not "works on my machine", but reproducible, testable, and safe to change. This episode covers three pillars: building a dotfiles repository with fzf as the centerpiece, reproducible installation via package managers and a tidy structure, and a testing strategy that runs every change against a throwaway configuration before it touches your main environment.
A dotfile is a file that starts with a dot — but a dotfiles repository is a deliberate project: your config tracked with git, so you can sync, roll back, and reproduce. For fzf, the centerpiece files are:
dotfiles/
├── .zshrc
├── .bashrc
├── .tmux.conf
├── .config/
│ ├── fzf/ # fzf-specific config
│ │ └── fzf.zsh # FZF_DEFAULT_OPTS and functions
│ ├── nvim/
│ └── git/
└── install.sh # a reproducible installerThe .config/fzf/fzf.zsh file is where the fzf-specific configuration lives — the place a project calls "the fzf config":
export FZF_DEFAULT_OPTS="--height 40% --layout=reverse --border --preview 'bat --color=always {}'"
export FZF_DEFAULT_COMMAND="fd --type f --hidden --exclude .git"
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"Tip
The discipline of a dotfiles repo is that every choice has a documented reason — a comment or a README line explaining why a --height or a keybinding exists. Six months later, your future self will read that file with fresh eyes; a repo without explanations is just a pile of magic.
Reproducibility means: the same command, the same result, on every machine. Two habits make an fzf setup reproducible.
1. Use a package manager with pinned versions. With Homebrew: brew install fzf — but also record the version in the repo (brew info fzf) so the install is a known state, not "whatever was latest". On Debian/Ubuntu, the .deb package from episode 19 is a precise, versioned target.
2. Keep the installer idempotent. An install.sh that detects what exists, skips what's already there, and installs only what's missing can be re-run safely:
if ! command -v fzf >/dev/null 2>&1; then
sudo apt-get install -y fzf
fi
if [ ! -d "$HOME/.config/fzf" ]; then
git clone https://github.com/junegunn/fzf.git "$HOME/.config/fzf"
fiinstall.sh --dry-run
install.sh --target ~/tmp-dotfiles-testWarning
A non-idempotent installer is a time bomb: run it twice and you may duplicate config, reinstall packages, or clobber files. Make every step conditional (if ! command -v, if [ ! -d ]) so the script is safe to run on a machine that's already configured — and test that by running it twice in a row.
Now the most important pillar — the one that turns "production-ready" from a slogan into a fact. Every change to the fzf config should be tested in a throwaway environment before it reaches your main config. The principle: never risk your daily driver on an untested idea.
Three practical techniques:
1. Test with a one-shot environment. A single command runs fzf with a fresh, minimal config — no dotfile needed:
FZF_DEFAULT_OPTS="--height 40% --layout=reverse" \
seq 100 | fzf2. Test the whole zsh config in a scratch shell. Instead of editing ~/.zshrc live, source it in a fresh shell and check the result. If the test shell misbehaves, you've lost nothing:
zsh --rcs3. Test in an ephemeral container. For the ultimate reproducibility test, run the installer inside a container — a disposable machine where the entire setup must work from scratch:
docker run --rm -it -v "$PWD":/dotfiles debian:latest \
bash -c "bash /dotfiles/install.sh && seq 100 | fzf --sync"Important
The throwaway test changes the psychology of configuration: an idea you can test is an idea you can keep — and an idea you can't test is a risk. Before you rebind a key, reload FZF_DEFAULT_OPTS, or swap --layout, run it in a scratch environment. If it works there, promote it; if it doesn't, you've protected your daily driver.
Putting the three pillars together, a production-ready fzf setup satisfies a checklist:
fzf --version recorded alongside the repo.Note
Notice the pattern this episode teaches: production isn't a state you reach once — it's a discipline you repeat. The install is re-tested, the config is re-read, the version is re-checked. That's what makes a setup production-ready, not the day it was born.
| Mistake | Symptom | Solution |
|---|---|---|
Editing ~/.zshrc live | A broken change breaks your shell | Test in a scratch shell first |
| A non-idempotent installer | Duplicate config on re-run | Make every step conditional |
| No version pinning | "Works on my machine" breaks elsewhere | Record fzf --version in the repo |
| Config without comments | Magic options six months later | Document the why of each choice |
| Testing only on your machine | Surprise breakage on a fresh box | Test the installer in a container |
| Mixing fzf config with random tweaks | The config file loses its purpose | Keep fzf config in its own .config/fzf/ file |
In this episode 21 you prepared a production-ready fzf setup: building a dotfiles repository with fzf as the centerpiece (FZF_DEFAULT_OPTS, FZF_DEFAULT_COMMAND), creating a reproducible installation that's idempotent and versioned through package managers and the .deb package, and testing every change in a throwaway environment — from one-shot FZF_DEFAULT_OPTS tests to a container that proves the setup works from scratch.
The message to take home: production-ready isn't a destination, it's a discipline — git-tracked config, idempotent installs, and a test-before-promote habit.
This is the last episode of the practical series — and every series deserves a closing chapter that zooms out. In the final episode 22 we reflect: alternative ecosystems & final reflection — fzf's place among other fuzzy finders, and the conclusions to take home from this whole journey.