Not every dotfile belongs on every machine. Your work laptop has VPN configs and corporate tooling. Your home machine has gaming scripts and personal API keys. Chezmoi's .chezmoiignore lets you keep everything in one repo but selectively ignore files based on which machine is running chezmoi apply.
The file .chezmoiignore lives in the root of your source state (~/.local/share/chezmoi/.chezmoiignore). It lists patterns of files that chezmoi should not manage — similar to .gitignore, but with a critical superpower: it's a template.
Because .chezmoiignore is processed as a Go template (even without a .tmpl extension), you can conditionally include or exclude patterns based on machine variables like hostname, OS, or custom data.
# ~/.local/share/chezmoi/.chezmoiignore
# Always ignore these
README.md
LICENSE
# Ignore work configs on personal machines
{{- if ne .chezmoi.hostname "work-laptop" }}
.config/corporate-vpn/
.config/work-slack-theme
.aws/config
{{- end }}
# Ignore personal configs on work machine
{{- if eq .chezmoi.hostname "work-laptop" }}
.config/gaming/
.local/bin/personal-backup.sh
{{- end }}
Key details about patterns:
.gitconfig), not the source path (e.g., dot_gitconfig)** matches across directory separators! to un-ignore it (excludes always take priority over includes)# (must be preceded by whitespace if mid-line)The template runs at apply-time on the current machine. On your work laptop, the work-specific block disappears and those files get managed. On your home machine, those same files get ignored — chezmoi won't touch them.
Chezmoi has two special files with very different behaviors:
| File | Behavior | Use when |
|---|---|---|
.chezmoiignore |
Chezmoi pretends the file doesn't exist in the source state. It won't create, update, or delete it in the target. | You want a file to exist in your repo but not be applied on certain machines. |
.chezmoiremove |
Chezmoi actively deletes matching files from the target on chezmoi apply. |
You want to ensure a file is gone — e.g., removing a deprecated config across all machines. |
The distinction matters: ignore means "don't manage this file, leave whatever is on disk alone." Remove means "delete this file from the target if it exists." Ignoring is passive; removing is active.
.chezmoiremove will delete files from your home directory on every chezmoi apply. Use it sparingly and deliberately. If you just want chezmoi to leave a file alone, .chezmoiignore is what you want.
Add a couple of files that only belong on one machine:
# Pretend these exist in your source state
chezmoi cd
mkdir -p dot_config/work-tools
echo "vpn-endpoint: corp.example.com" > dot_config/work-tools/vpn.yaml
mkdir -p dot_config/personal
echo "backup-target: /Volumes/NAS" > dot_config/personal/backup.yaml
exit
Create the ignore file in your source state:
chezmoi cd
cat > .chezmoiignore << 'EOF'
# Files that should never be applied anywhere
README.md
LICENSE
*.bak
# Work-only configs — ignore on personal machines
{{- if ne .chezmoi.hostname "work-laptop" }}
.config/work-tools/**
{{- end }}
# Personal-only configs — ignore on work machine
{{- if eq .chezmoi.hostname "work-laptop" }}
.config/personal/**
{{- end }}
EOF
exit
Chezmoi gives you two commands to inspect the state:
# Show all files chezmoi WILL manage on this machine
chezmoi managed
# Show all files chezmoi is IGNORING on this machine
chezmoi ignored
On your personal machine, you should see .config/work-tools/vpn.yaml in the ignored list. On your work laptop, .config/personal/backup.yaml would be ignored instead.
You can preview what would happen on a different machine by overriding template data:
# See what the ignore file renders to for a hypothetical machine
chezmoi execute-template < ~/.local/share/chezmoi/.chezmoiignore
chezmoi cd
git add .chezmoiignore dot_config/
git commit -m "chore: add machine-conditional ignore rules"
git push
exit
Beyond hostname, you can branch on any template variable:
# OS-based ignoring
{{- if eq .chezmoi.os "linux" }}
Library/**
{{- end }}
{{- if eq .chezmoi.os "darwin" }}
.config/i3/**
.config/polybar/**
{{- end }}
# Custom data from .chezmoi.toml
{{- if not .personal }}
.config/personal/**
{{- end }}
The .personal variable above would come from your ~/.config/chezmoi/chezmoi.toml:
[data]
personal = true
You can place .chezmoiignore files inside source state subdirectories too. A .chezmoiignore inside dot_config/ only applies to files within .config/. This keeps your root ignore file from growing unwieldy.
| Command | What it did |
|---|---|
.chezmoiignore | Templated list of patterns chezmoi won't manage |
.chezmoiremove | List of patterns chezmoi will actively delete from target |
chezmoi managed | Shows files chezmoi will apply on this machine |
chezmoi ignored | Shows files chezmoi is skipping on this machine |
chezmoi execute-template | Renders a template with current machine data (useful for debugging) |
.chezmoiignore different from a regular .gitignore?.chezmoiignore is always processed as a template, even without a .tmpl extension. This means you can use {{ if }} blocks to conditionally ignore files based on hostname, OS, or custom data..chezmoiignore is always processed as a Go template — you can use {{ if }} blocks to conditionally ignore different files on different machines. No .tmpl extension required..chezmoiignore and .chezmoiremove?.chezmoiignore means "pretend this doesn't exist in my source" (leave the target alone). .chezmoiremove means "actively delete this from the target on apply.".chezmoiignore match against source paths or target paths?.gitconfig, not dot_gitconfig..chezmoiignore always match against the target path (e.g., .gitconfig), not the source state name (e.g., dot_gitconfig).You can now keep machine-specific files in one repo without them leaking across machines. In Lesson 7: Edit Workflow, you'll learn the day-to-day editing loop — how to modify managed files, preview changes, and keep source and target in sync without surprises.
chezmoi .chezmoiignore reference — The full spec including pattern syntax, subdirectory behavior, and exclude (!) rules. ~3 minute read.