Ignore & Exclude Per Machine

Lesson 6 · chezmoi · ~8 minutes

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.

How .chezmoiignore Works

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:

Key insight

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.

Ignore vs. Remove: Two Different Things

Chezmoi has two special files with very different behaviors:

FileBehaviorUse 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.

Be careful with .chezmoiremove

.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.

Exercise: Conditional Ignoring Per Machine

Step 1: Create some machine-specific files

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

Step 2: Create .chezmoiignore with conditionals

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

Step 3: Verify what's managed vs. ignored

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.

Step 4: Test with a different hostname

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

Step 5: Commit

chezmoi cd
git add .chezmoiignore dot_config/
git commit -m "chore: add machine-conditional ignore rules"
git push
exit

Common Patterns

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
Subdirectory ignores

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.

What just happened

CommandWhat it did
.chezmoiignoreTemplated list of patterns chezmoi won't manage
.chezmoiremoveList of patterns chezmoi will actively delete from target
chezmoi managedShows files chezmoi will apply on this machine
chezmoi ignoredShows files chezmoi is skipping on this machine
chezmoi execute-templateRenders a template with current machine data (useful for debugging)

Knowledge check

What makes .chezmoiignore different from a regular .gitignore?
Correct. .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.
Not quite. The key differentiator is that .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.
What is the difference between .chezmoiignore and .chezmoiremove?
Right. Ignore is passive — chezmoi won't touch the file at all (won't create, update, or delete it). Remove is active — chezmoi will delete matching files from your home directory on every apply.
The key distinction is passive vs. active. .chezmoiignore means "pretend this doesn't exist in my source" (leave the target alone). .chezmoiremove means "actively delete this from the target on apply."
Do patterns in .chezmoiignore match against source paths or target paths?
Correct. Patterns always match against the target path — what the file will be called in your home directory. So you write .gitconfig, not dot_gitconfig.
Patterns in .chezmoiignore always match against the target path (e.g., .gitconfig), not the source state name (e.g., dot_gitconfig).

Next up

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.

Recommended Reading

chezmoi .chezmoiignore reference — The full spec including pattern syntax, subdirectory behavior, and exclude (!) rules. ~3 minute read.

Questions? Ask me anything about ignore patterns, conditional logic in templates, or how to structure your ignore file for multiple machines.
← Prev Next →