The .secrets file is not the only game in town. For certain environments, alternatives exist:
| Tool/Method | Strengths | Weaknesses |
|-------------|-----------|-------------|
| macOS Keychain | OS-level encryption, per-app access | Painful from CLI, not cross-platform |
| Systemd Credentials | Excellent for Linux services | Useless for development |
| HashiCorp Vault | Dynamic secrets, audit logs, leasing | Operational overhead |
| AWS Parameter Store | Free tier, integrates with IAM | Vendor lock-in, no local caching |
| Git-crypt | Encrypts specific files in Git transparently | Requires GPG, doesn't prevent leaks (just hides them) |
For most startups and small teams, SOPS + Age with a committed .secrets.enc.yaml file strikes the best balance: Git-friendly encryption without a server to manage.
Why do brilliant engineers commit secrets? Not because they're careless. Because friction breeds shortcuts.
When developers face a choice between:
They will choose the path of least resistance. That path often begins with commenting out the gitignore line "just for this one test" and ends with a public repo on GitHub.
The solution is to reduce friction. Make generating a secure, local .secrets file a one-command operation:
make secrets # reads from Vault, writes .secrets with limited permissions
Better yet, use a tool like direnv that loads .env files into the environment automatically upon cd—and unloads them when you leave.
If you find a .secrets file in Git history, changing the key is mandatory. If you cannot change the key (e.g., a hardcoded SSL private key), you must use git filter-branch or BFG Repo-Cleaner to purge it from existence.
Warning: Rewriting history breaks forks and PRs. Do this only during a scheduled maintenance window.
.secrets May 2026
The .secrets file is not the only game in town. For certain environments, alternatives exist:
| Tool/Method | Strengths | Weaknesses |
|-------------|-----------|-------------|
| macOS Keychain | OS-level encryption, per-app access | Painful from CLI, not cross-platform |
| Systemd Credentials | Excellent for Linux services | Useless for development |
| HashiCorp Vault | Dynamic secrets, audit logs, leasing | Operational overhead |
| AWS Parameter Store | Free tier, integrates with IAM | Vendor lock-in, no local caching |
| Git-crypt | Encrypts specific files in Git transparently | Requires GPG, doesn't prevent leaks (just hides them) |
For most startups and small teams, SOPS + Age with a committed .secrets.enc.yaml file strikes the best balance: Git-friendly encryption without a server to manage. .secrets
Why do brilliant engineers commit secrets? Not because they're careless. Because friction breeds shortcuts.
When developers face a choice between:
They will choose the path of least resistance. That path often begins with commenting out the gitignore line "just for this one test" and ends with a public repo on GitHub.
The solution is to reduce friction. Make generating a secure, local .secrets file a one-command operation: They will choose the path of least resistance
make secrets # reads from Vault, writes .secrets with limited permissions
Better yet, use a tool like direnv that loads .env files into the environment automatically upon cd—and unloads them when you leave.
If you find a .secrets file in Git history, changing the key is mandatory. If you cannot change the key (e.g., a hardcoded SSL private key), you must use git filter-branch or BFG Repo-Cleaner to purge it from existence. Better yet, use a tool like direnv that loads
Warning: Rewriting history breaks forks and PRs. Do this only during a scheduled maintenance window.