I used KeePass for years. Then 1Password. Then Bitwarden. All decent tools, but every one of them felt like too much. Too much UI, too many features, too much friction to wire into the way I actually work. Every time I reached for a password I was reaching across an app boundary, and that small interruption added up.
Then I found pass. It does exactly what the name promises: it stores passwords. I want to walk you through it the way I learned it, starting with the one command that hooked me, then adding layers until you can see my full setup.
What is pass?
Pass calls itself the “standard unix password manager.” Under the hood it is a shell script of roughly 700 lines that stores each password as a GPG-encrypted file in a directory. No database. No proprietary format. No cloud sync bolted on. The whole thing is small enough that you can read the source in an afternoon, which matters to me: when something breaks, I want to be able to find out why.
~/.password-store/
├── email/
│ ├── gmail.gpg
│ └── protonmail.gpg
├── social/
│ └── github.gpg
└── work/
├── gitlab.gpg
└── jira.gpg
Each .gpg file is an encrypted text file holding your password and, if you want, some extra info. The directory structure is your organization. That is the entire mental model.
The simplest version: working in five minutes
Installation
# macOS
brew install pass gnupg
# Debian/Ubuntu
sudo apt install pass gnupg
# Arch
sudo pacman -S pass gnupg
You need a GPG key
Pass uses GPG for encryption, so you need a key. If you don’t have one yet:
gpg --full-generate-key
Choose RSA, 4096 bits, and fill in your name and email. Remember your passphrase. You will need it every time you decrypt a password, and nobody can recover it for you.
Initialize the password store
# Use your GPG key ID or email
pass init "tom@example.com"
This creates ~/.password-store/ with a .gpg-id file recording which GPG key is in use.
Your first password
# Generate a new password
pass generate email/gmail 24
# Or add an existing password
pass insert social/github
That is the whole setup. You now have a working password manager.
Retrieve a password
# Show password in terminal
pass email/gmail
# Copy to clipboard (disappears after 45 sec)
pass -c email/gmail
This was the moment it clicked for me. No app to launch, no extension to wake up. One command and the password lands in my clipboard.
Layer one: why this fits my workflow
Pass slots into a terminal-first workflow without asking me to leave it. When I need a work password:
pass -c work/gitlab
Done. It is in my clipboard for thirty seconds and then gone.
Because pass is just files in a directory, a few things fall out for free:
- It’s searchable:
pass find gitlabor justls ~/.password-store/ - It’s scriptable:
pass show -c $(pass find jira | head -1) - It integrates with everything: dmenu, rofi, fzf, Alfred, your own scripts
A .gpg file can hold more than a password. The convention is simple: the first line is the password, everything after it is metadata.
pass edit email/gmail
SuperSecurePassword123!
---
username: tom@gmail.com
url: https://mail.google.com
otp: otpauth://totp/Gmail:tom@gmail.com?secret=JBSWY3DPEHPK3PXP
notes: recovery email is backup@proton.me
You can even pull TOTP (2FA) codes straight out of it:
# With pass-otp extension
pass otp email/gmail
Layer two: git sync, the part that sealed it
Pass has built-in git support, and this is the reason I stopped looking at other password managers.
# Initialize git repo
pass git init
# Every change is automatically committed
pass generate new/password 20
# → [master 1a2b3c4] Add generated password for new/password.
# Push to remote
pass git push
Your password store is now a git repository. That gives you:
- Automatic backups to your git remote
- Sync between machines with just
pass git pull - Version history of every password
- Conflict resolution when you change the same thing on two machines
Mine lives in a private GitLab repo. Setting up a fresh machine is one clone:
git clone git@gitlab.com:tom/password-store.git ~/.password-store
Every password, available. There is no vendor in the middle of that pull, which is the whole point.
Browser integration
“But I want auto-fill in my browser.”
You can have it. There are extensions for Firefox and Chrome:
- Browserpass - native messaging, works well
- passff - Firefox-only, also solid
Browserpass reads your password store, matches the URL against your directory structure, and fills the form. It works better than I expected.
~/.password-store/
├── github.com/
│ └── tom.gpg # auto-matched on github.com
├── gitlab.com/
│ └── work.gpg
└── mail.google.com/
└── personal.gpg
Fuzzy finding with fzf
This is my daily driver. A small script:
#!/bin/bash
# passfzf - fuzzy find and copy password
password=$(find ~/.password-store -name "*.gpg" | \
sed 's|.*/\.password-store/||; s|\.gpg$||' | \
fzf --height 40% --reverse)
[[ -n "$password" ]] && pass -c "$password"
Bind it to a hotkey and you get instant lookup with fuzzy matching. If you live in rofi instead, rofi-pass does the same job:
rofi-pass
Advanced patterns
Multi-key encryption
Sharing passwords with a team? Pass supports multiple GPG keys:
pass init key1@example.com key2@example.com
Now both keys can decrypt everything. You can also scope different keys per directory:
# Only you have access to personal/
echo "your-key-id" > ~/.password-store/personal/.gpg-id
# The whole team has access to shared/
echo -e "key1\nkey2\nkey3" > ~/.password-store/shared/.gpg-id
pass init
Extensions worth knowing
Pass has an extension system. The ones I reach for:
pass-otp for TOTP/HOTP support:
# Add OTP
pass otp insert email/gmail
# Paste the otpauth:// URL
# Generate code
pass otp email/gmail
# → 482193
pass-tomb wraps your entire store in a Tomb container:
pass tomb open
# do your thing
pass tomb close
That adds a layer if someone has physical access to your machine.
pass-update for bulk rotation:
pass update -l 32 work/*
The real downside: key management
Here is the honest trade-off. Pass is simple precisely because it leans on GPG, and GPG key management is anything but simple. This is the cost of sovereignty, and pretending otherwise would be dishonest.
Your GPG key is critical
Lose your GPG private key and you lose every password. Permanently. No “forgot password” link, no support desk that can dig you out.
So:
- Back up your GPG key in more than one place
- Remember your passphrase (writing it on paper in a safe is a reasonable move)
- Consider a hardware key like a YubiKey
GPG can be frustrating
GPG is powerful and notoriously unfriendly. You will meet errors like these:
gpg: decryption failed: No secret key
gpg: problem with the agent: No pinentry
gpg: public key not found
If you haven’t used GPG before, the learning curve is steep. Pinentry popups that refuse to appear, agents that hang, keys that go missing. I have lost evenings to it, and I am telling you that up front.
No built-in mobile app
There is no official pass app. Third-party options exist:
- Android: Password Store - works well, syncs via git
- iOS: Pass for iOS - also git sync
Neither is as polished as 1Password or Bitwarden on mobile. You have to configure git credentials and import your GPG key first, and that takes time.
No password sharing via link
“Share this password with a colleague” is not a feature. Multi-key encryption works, but it requires everyone to hold GPG keys. For a quick share with someone non-technical, pass is the wrong tool.
Sync conflicts can be tricky
Git sync is great until you change the same password on two machines and get a merge conflict in an encrypted file. Resolving that is no fun. In practice it rarely happens if you run pass git pull before making changes, but it can.
When pass is the right call
Pass is ideal if:
- You’re comfortable in the terminal
- You already use GPG, or you’re willing to learn
- You want control over your data with no cloud unless you choose one
- You want to wire it into scripts and automation
- You want something simple and auditable (roughly 700 lines of bash)
When to choose something else
Reach for Bitwarden or 1Password if:
- You share passwords with non-technical people (family, colleagues without GPG)
- You want a polished mobile experience with no setup
- You’d rather not deal with GPG key management
- Your organization mandates a specific password manager for compliance
The full picture: my setup
Here is how I actually run it, building on everything above:
# ~/.zshrc
export PASSWORD_STORE_DIR="$HOME/.password-store"
export PASSWORD_STORE_CLIP_TIME=30
# Fuzzy find alias
alias p='passfzf'
# Quick copy
alias pc='pass -c'
The store lives in a private GitLab repo. I sync between laptop, desktop, and phone with git. The GPG key sits on a YubiKey, with a backup on an air-gapped machine.
Is it more setup than Bitwarden? Yes. The trade-off buys me a workflow that never leaves the terminal, complete control over my data, and no vendor who can raise prices or sell the company out from under me next quarter.
Wrapping up
Pass suits people who like the Unix philosophy: do one thing, do it well, integrate with everything else. The GPG dependency alone rules it out for plenty of people, and I’d rather say that plainly than sell it to the wrong audience.
But if you have a terminal-first workflow, you want control over your data, and you’re willing to climb the GPG learning curve, pass is a relief after every overengineered manager I tried before it. Roughly 700 lines of bash, files in a directory, git for sync. It does the job and gets out of the way.
Sometimes simple really is better.
Resources:
- passwordstore.org - official site
- pass git repo - source code
- Browserpass - browser extension
- Password Store (Android) - Android app
