Doppler is an established server-side secrets product. Their public security write-up describes a two-tier design: encryption operations run on infrastructure that is not exposed to the public internet, with secrets tokenized and ciphertext returned through the customer-facing tier. The design keeps raw plaintext off internet-facing servers. Capy is built around a different choice. The Doppler model relies on Doppler’s own infrastructure to perform encryption: your client sends plaintext over TLS, Doppler encrypts. Capy’s CLI encrypts each value on the engineer’s machine before any of it leaves, using a key whose outer wrap the service holds and whose inner wrap stays on the client. The Capy service stores ciphertext and never holds the material to decrypt. Both designs are reasonable; they answer different questions about who needs to be trusted, and what a breach actually exposes.Documentation Index
Fetch the complete documentation index at: https://capy.sc/docs/llms.txt
Use this file to discover all available pages before exploring further.
At a glance
| Capy | Doppler | |
|---|---|---|
| Where encryption happens | On the client, before any wire transit | On Doppler infrastructure, after TLS upload |
| What the service stores | Ciphertext only | Plaintext through the encryption tier; ciphertext at rest in the database tier |
| Vendor can decrypt | No — the service never holds the inner wrap | Yes — Doppler’s infrastructure has a path to plaintext |
| Removing a teammate | capy kick — cryptographic, no rotation needed | Permission flip; rotate anything sensitive |
| Secret diffs in PR review | keep.lock manifest with hash references | Changes happen in the dashboard or API, outside the repo |
| Git-branch alignment | Branches pin to your git branches | Configs and environments, not git branches |
| Hosted dashboard for non-engineers | No — CLI-first | Yes — broad dashboard surface |
| Built-in SaaS integrations | Narrower by design | Many, across CI and runtime targets |
| AI-agent blast radius | Only what capy run -- is currently injecting | Anything the authenticated machine can fetch |
What this looks like at the request path
Picture the same workflow under each product. An engineer adds a new value,STRIPE_SECRET_KEY. Under Doppler, the value goes over TLS to Doppler’s API, the encryption tier wraps it, and the ciphertext lands in the database tier. Under Capy, the value is encrypted on the engineer’s machine; only the ciphertext is uploaded to the service, which syncs it to teammates’ machines. In each case the value is available at runtime via a one-line invocation (doppler run -- ..., capy run -- ...); the difference is what the vendor’s infrastructure ever held.
Both tools handle the day-to-day operations a developer cares about: pushing a new value, switching environments, fetching at deploy. Capy adds two things Doppler does not. The keep.lock manifest lives in your git repo as a committable list of hash references, so a code reviewer can see in a PR diff which secrets changed, without seeing the values. And capy kick removes a teammate by destroying the service-side wrap material on their key, which makes their local key material inert without requiring the rest of the team to rotate or re-encrypt anything. Doppler’s revocation is permission-based; the safe move is to flip the access flag and rotate anything sensitive.
When Doppler is a good fit
Teams whose buying criteria centers on a hosted dashboard for non-CLI stakeholders, many built-in integrations into a long list of SaaS targets, or compliance certifications obtained against a server-side architecture will find Doppler a good fit. The trusted-vendor model is widely accepted in regulated workloads where the vendor is already in scope, and Doppler has staffed for that.When Capy is the better answer
If “the vendor cannot decrypt our secrets” needs to be a built-in property rather than a configuration setting (common for teams handling customer keys, sovereign data, or for teams that want a breach to come out as “ciphertext was exfiltrated, the attacker has bytes”), Capy’s request path is the answer. Likewise if your secret changes belong in code review (thekeep.lock manifest makes that legible without exposing values), or if removing a teammate should be a one-command event rather than a rotate-everything ritual.
The same trade-off has become more important as AI coding agents joined the dev loop. Doppler authenticates the developer’s machine for the project; whatever that machine can fetch, an agent process running on the same machine can fetch too. Capy decrypts only what capy run -- is actively injecting; values not currently in scope stay as ciphertext on disk. An exfiltrated .env is just bytes. A prompt-injected agent gets only what’s currently in scope, not the full project. The comparisons overview covers this in more detail.
Pulling values out of Doppler when you migrate is straightforward: doppler secrets download --no-file --format json produces a JSON dump per config, which loads into a fresh Capy project one branch at a time. The whole exercise is usually an evening on a small project.
The deciding question, said plainly: what does a breach of your secrets vendor cost you? If “we’d rotate and survive” is acceptable, Doppler will serve. If there are values that must remain unreadable to the vendor (even encrypted, even at rest, even with separated infrastructure), the request-path difference is what you’re buying.