Quickstart: dotfiler + zdot from scratch
June 11, 2026 · View on GitHub
This guide gets you from nothing to a working dotfiles repo managed by dotfiler with zdot handling your zsh configuration. It assumes macOS or Linux with git and zsh already installed.
Why this setup?
zdot organizes what's inside your .zshrc; dotfiler manages the rc files
themselves -- your .zshrc/.zshenv, the rest of ~/.config, and your user
modules live as symlinks into one versioned git repo that reaches every
machine. zdot registers as a dotfiler update hook, so a single login-time
check updates your dotfiles, rc files, and zdot together; as a submodule, the
exact zdot version is pinned in your dotfiles history. See
the README for the full
rationale, and dotfiler's
zdot-integration
and
how-updates-work
docs for the update lifecycle (the two-round model, topologies, and release
channels).
Neither tool requires the other -- for standalone zdot, use the README Quick Start instead.
What you end up with
~/.dotfiles/ ← your dotfiles git repo
.config/
zdot/ ← zdot (git submodule)
dotfiler/
hooks/
zdot.zsh -> ../../zdot/core/dotfiler-hook.zsh
zsh/
.zshrc ← your zshrc, managed by dotfiler
~/.config/ ← linktree (symlinks into ~/.dotfiles)
zdot/ -> ~/.dotfiles/.config/zdot/
zsh/ -> ~/.dotfiles/.config/zsh/
dotfiler keeps ~/.dotfiles up to date and manages the ~/.config symlink
tree. zdot loads from ~/.config/zdot at shell startup.
dotfiler defaults to ~/.dotfiles as the repo location. If you want it
elsewhere, set DOTFILES in your environment.
Step 1 — Create your dotfiles repo
mkdir -p ~/.dotfiles
cd ~/.dotfiles
git init
Step 2 — Install dotfiler
git clone https://github.com/georgeharker/dotfiler ~/.dotfiles/.nounpack/dotfiler
Add dotfiler's CLI to your PATH temporarily so you can use it before zdot is
wired up:
export PATH="$HOME/.dotfiles/.nounpack/dotfiler:$PATH"
Step 3 — Add zdot as a submodule
cd ~/.dotfiles
git submodule add https://github.com/georgeharker/zdot .config/zdot
git submodule update --init --recursive
Step 4 — Create a minimal .zshrc
Create ~/.dotfiles/.config/zsh/.zshrc:
# Source zdot
source "${XDG_CONFIG_HOME:-$HOME/.config}/zdot/zdot.zsh"
# Load the modules you want — start minimal, add more later.
# xdg + bootstrap are the foundation; nearly everything depends on them.
zdot_load_module xdg
zdot_load_module bootstrap
zdot_load_module env
zdot_load_module history
zdot_load_module brew # macOS only
zdot_load_module completions
# Run everything
zdot_init
Commit it:
cd ~/.dotfiles
git add .config/zsh/.zshrc
git commit -m "add initial zshrc"
Step 5 — Register the zdot hook with dotfiler
This creates a symlink in your repo that tells dotfiler zdot is a managed component:
dotfiler setup --bootstrap-hook ~/.dotfiles/.config/zdot/core/dotfiler-hook.zsh --yes
Step 6 — Unpack the linktree
dotfiler setup -u
This creates the symlinks in ~/.config/ and installs the hook at
~/.config/dotfiler/hooks/zdot.zsh. After this step your shell is live.
Step 7 — Enable zdot self-updates (optional)
Add to your .zshrc before zdot_init:
zstyle ':zdot:update' mode prompt # ask before updating at shell start
And for submodule pin auto-commits (so the dotfiles repo tracks zdot's version):
zstyle ':dotfiler:update' in-tree-commit auto
Step 8 — Start a new shell
exec zsh
zdot loads, modules initialise in dependency order, and dotfiler will check for updates at the next login shell.
Day-to-day
| Task | Command |
|---|---|
| Pull updates for dotfiles + zdot | dotfiler update |
| Re-unpack after manual repo changes | dotfiler setup -u |
| Add a new module | zdot_load_module <name> in .zshrc, then exec zsh |
| Customise a built-in module | zdot module clone <name> |
| Debug zdot loading | zdot info or zdot debug |
Bootstrap on a new machine
Once your dotfiles repo is on a remote (GitHub, etc.) and you're setting up a new machine:
# 1. Clone your dotfiles
git clone <your-repo-url> ~/.dotfiles
# 2. Clone dotfiler
git clone https://github.com/georgeharker/dotfiler ~/.dotfiles/.nounpack/dotfiler
export PATH="$HOME/.dotfiles/.nounpack/dotfiler:$PATH"
# 3. Bootstrap — initializes submodules (zdot included), reads hooks from
# the repo, unpacks everything (no linktree needed yet)
dotfiler setup --bootstrap
After --bootstrap completes the linktree is in place and subsequent shells
use dotfiler update as normal.
Further reading
- dotfiler zdot-integration.md — full reference: topology options, update lifecycle, symlink chain details
- using-plugins.md — loading plugins and configuring shipped modules
- zstyle-reference.md — all configuration options
- module-guide.md — writing your own modules