Your dotfiles live in a git repo. That repo should never contain secrets — API tokens, passwords, private keys. But your configs often need those values. Chezmoi solves this by pulling secrets from your system's keychain at apply time, so the actual values never touch your source state.
The source state is a git repo. Even if it's private, secrets in git are dangerous:
The rule is simple: templates reference secrets by name, never by value. The actual secret lives in a secure store (Keychain, 1Password, etc.) and is injected only when chezmoi renders the template.
Chezmoi uses the keyring template function to read from macOS Keychain (via the go-keyring library). On macOS this maps directly to Keychain Access. On Linux it uses GNOME Keyring, and on Windows it uses Credentials Manager.
keyring FunctionThe template function signature is:
{{ keyring "service-name" "account-name" }}
This reads a password from the keychain matching the given service and account. You set values using chezmoi's CLI:
chezmoi secret keyring set --service=github --user=your-username
Chezmoi will prompt you for the value. It gets stored in macOS Keychain — you can verify it appears in Keychain Access.app under the service name you chose.
To retrieve it from the command line (useful for debugging):
chezmoi secret keyring get --service=github --user=your-username
You can use chezmoi's built-in command, or the macOS security CLI directly. Let's use chezmoi since that's what you'll use in practice:
chezmoi secret keyring set --service=chezmoi-lesson --user=demo-token
When prompted, type my-super-secret-value and press Enter.
You can also store secrets with Apple's security command. This is what happens under the hood:
security add-generic-password -s "chezmoi-lesson" -a "demo-token" -w "my-super-secret-value"
Both approaches write to the same keychain. Use whichever fits your workflow — chezmoi's command is simpler, but security is useful for automation scripts.
Create a chezmoi-managed file that references the keychain value:
chezmoi edit ~/.config/demo-secret.env
Add this content:
# This file is managed by chezmoi — do not edit directly.
DEMO_TOKEN={{ keyring "chezmoi-lesson" "demo-token" }}
chezmoi cat ~/.config/demo-secret.env
You should see:
# This file is managed by chezmoi — do not edit directly.
DEMO_TOKEN=my-super-secret-value
The secret is injected at render time. If you look at the source state, you'll only see the {{ keyring ... }} call — never the actual value.
chezmoi apply ~/.config/demo-secret.env
cat ~/.config/demo-secret.env
The target file contains the real secret. The source state stays clean.
chezmoi forget ~/.config/demo-secret.env
rm ~/.config/demo-secret.env
security delete-generic-password -s "chezmoi-lesson" -a "demo-token"
Here's how you'd actually use this for a GitHub personal access token:
# Store the token
chezmoi secret keyring set --service=github --user=your-github-username
Then in your .gitconfig template (dot_gitconfig.tmpl):
[user]
name = Your Name
email = you@example.com
[github]
user = {{ .github.user | quote }}
token = {{ keyring "github" .github.user | quote }}
The | quote pipe wraps the value in quotes, which is good practice for values that might contain special characters.
Chezmoi integrates with many secret backends beyond Keychain. If you use one of these, the same principle applies — templates reference secrets by name:
| Manager | Template function |
|---|---|
| 1Password | onepasswordRead "op://vault/item/field" |
| Bitwarden | bitwarden / rbw |
| LastPass | lastpass "item-name" |
| pass | pass "path/to/secret" |
| Vault (HashiCorp) | vault "path" |
Each manager has its own setup and authentication flow. The chezmoi docs cover each one in detail. For this course, we focus on Keychain since it's built into macOS and requires no extra software.
If you need to store entire secret files (not just individual values), chezmoi supports age encryption. You encrypt files in the source state and chezmoi decrypts them at apply time. This is useful for SSH keys or full credential files where a template approach doesn't make sense.
Set it up with chezmoi age keygen and configure encryption in .chezmoi.toml. We won't cover it in depth here, but it's good to know the option exists.
keyring function takes a service name and account name. It works across macOS Keychain, GNOME Keyring, and Windows Credentials Manager.keyring. It takes two arguments: service name and account name. It's cross-platform — on macOS it reads from Keychain, on Linux from GNOME Keyring.{{ keyring "name" "account" }}.chezmoi secret keyring set --service=name --user=account. This stores the value in macOS Keychain. You can also use the security CLI directly, but chezmoi's command is the standard approach.Your source state is getting more sophisticated — templates, scripts, and now secrets pulled from Keychain. But not every file belongs in chezmoi. In Lesson 6: Ignore & Exclude, you'll learn to control what chezmoi tracks and what it leaves alone, keeping your source state focused.
chezmoi: Keychain and Windows Credentials Manager — The official docs for keyring integration. Also covers the secret generic command for custom password managers. ~3 minute read.