Here's something nobody talks about.
.gitignore doesn't encrypt your secrets. It just hides them from git.
They're still sitting on your laptop as plaintext. Every tool you install can read them. Every script that runs can read them. One accidental commit and your database password is public on GitHub forever.
So I built dotlock — an encrypted .env vault with a terminal UI, written in Go.
Before and after
Before dotlock
DATABASE_URL=postgres://localhost/myapp # plaintext, readable by anything
STRIPE_KEY=sk_live_abc123 # one grep away from anyone
After dotlock
# .dotlock file on disk — looks like this:
[encrypted binary — unreadable without your private key]
How it works under 10 seconds
cd my-project
dotlock set DATABASE_URL # prompts for value, input is masked
dotloc # opens the terminal UI
Secrets are encrypted with age — X25519 key agreement and ChaCha20-Poly1305 authenticated encryption. The same primitives serious security engineers use. No master password. No cloud. No telemetry. 100% offline.
What it looks like

Two panels — profiles on the left, secrets on the right. Values are masked by default. Press v to reveal for 30 seconds, then it hides itself automatically.
Switch between dev, staging, and prod profiles. Run a diff before deploying to catch missing variables before they break your app.
The interesting technical bit
The hardest part wasn't the encryption — filippo.io/age makes that straightforward.
It was the TUI.
BubbleTea uses the Elm architecture — Model, Update, View. Everything is a message. A keypress is a message. A timer firing is a message. Your Update function receives messages and returns a new model.
The 30-second auto-hide on secret reveal works like this — no time.Sleep, no goroutines:
type secretReveal struct {
key string
value []byte
expire time.Time // Now() + 30 seconds
}
On every render, check if time.Now() is past the expiry. If it is, zero the bytes and clear the display. Simple once you understand the model but it took me longer than I expected to get right.
Install it
go install github.com/ahmadraza100/dotlock@latest
cd your-project
dotlock init
dotlock ui
Or download a binary from the releases page — Mac, Linux, and Windows all supported.
Full source, architecture docs, and security model on GitHub:
👉 github.com/ahmadraza100/dotlock
What do you currently use for managing local secrets? Curious what others are doing — drop it in the comments.
Top comments (0)