Hardcoded credentials in source code remain one of the leading causes of cloud breaches. The fix sounds simple — use a secrets manager — but picking between Vault, AWS Secrets Manager, and Doppler involves real trade-offs in operational complexity, cost, and developer workflow friction.
What You're Actually Comparing
These three tools represent different philosophies, not just different implementations:
- HashiCorp Vault: open-source, self-hosted (or managed via HCP Vault), feature-rich, with a steep operational learning curve.
- AWS Secrets Manager: fully managed, deeply integrated with IAM, priced per secret and per API call.
- Doppler: developer-focused SaaS that treats secrets like environment variables with proper access control.
Comparing them on price alone misses the point. The real questions are: who manages the infrastructure, how granular is your access control, and how painful is onboarding a new developer?
Developer Experience and Setup
Vault requires the most upfront work. You spin up a server (or use vault server -dev locally), choose an auth method (AppRole, Kubernetes, AWS IAM, LDAP...), write policies, and define secret mounts. For teams with dedicated infrastructure engineers, this is manageable. For a three-person startup, it's often overkill.
AWS Secrets Manager has near-zero setup if you're already on AWS. You create a secret via the console or CLI, attach an IAM policy to your service role, and start reading. The friction is the IAM complexity you already have — not something Secrets Manager adds.
Doppler's pitch is "you shouldn't need to read documentation." You sign up, create a project, add secrets in a UI that looks like a spreadsheet, and inject them into your process with doppler run -- python app.py. Secrets are scoped by environment (dev/staging/prod) by default.
Here's how fetching a secret looks in Python for each:
# Vault — using hvac
import hvac, os
client = hvac.Client(url=os.environ["VAULT_ADDR"], token=os.environ["VAULT_TOKEN"])
secret = client.secrets.kv.v2.read_secret_version(path="myapp/db", mount_point="secret")
password = secret["data"]["data"]["password"]
# AWS Secrets Manager — using boto3
import boto3, json
def get_secret(name: str, region: str = "eu-west-1") -> dict:
client = boto3.client("secretsmanager", region_name=region)
return json.loads(client.get_secret_value(SecretId=name)["SecretString"])
password = get_secret("prod/myapp/db")["password"]
# Doppler — environment variables injected by the CLI
import os
password = os.environ["DB_PASSWORD"]
# Or programmatically via the REST API
import httpx
def get_doppler_secret(name: str, token: str) -> str:
resp = httpx.get(
"https://api.doppler.com/v3/configs/config/secret",
params={"name": name},
headers={"authorization": f"Bearer {token}"},
)
resp.raise_for_status()
return resp.json()["secret"]["value"]["raw"]
Secret Rotation and Dynamic Credentials
This is where Vault separates itself from the pack. Vault supports dynamic secrets — instead of storing a fixed password for your database, Vault generates fresh credentials on demand with a configurable TTL. When the lease expires, Vault revokes them automatically. There's no rotation job to write or schedule.
Here's how you'd request dynamic database credentials in Go:
package main
import (
"context"
"os"
vault "github.com/hashicorp/vault-client-go"
)
func getDBCredentials(ctx context.Context) (string, string, error) {
client, err := vault.New(
vault.WithAddress(os.Getenv("VAULT_ADDR")),
)
if err != nil {
return "", "", err
}
client.SetToken(os.Getenv("VAULT_TOKEN"))
resp, err := client.Secrets.DatabaseGenerateCredentials(
ctx,
"myapp-role",
vault.WithMountPath("database"),
)
if err != nil {
return "", "", err
}
return resp.Data["username"].(string), resp.Data["password"].(string), nil
}
AWS Secrets Manager supports automatic rotation via Lambda. AWS provides ready-made templates for RDS, Redshift, and DocumentDB. It works well within the AWS ecosystem, but rotation is schedule-based rather than on-demand — your app still caches a long-lived secret between rotation events and must handle the brief window when old credentials expire.
Doppler has no built-in rotation mechanism. You update secrets manually or via API, and Doppler syncs the new value to connected integrations (GitHub Actions secrets, Kubernetes Secrets, Vercel env vars, etc.). For static API keys that change infrequently, this is fine. For database passwords or short-lived tokens, you need a rotation layer upstream.
Cost and Operational Overhead
| Vault (self-hosted) | AWS Secrets Manager | Doppler | |
|---|---|---|---|
| Base infrastructure | Your servers | None | SaaS (~$6/user/month) |
| Per-secret cost | None | $0.40/secret/month | None |
| Per-call cost | None | $0.05/10k API calls | None |
| Operational burden | High | Low | None |
| Cross-cloud | Yes | AWS only | Yes |
| Dynamic secrets | Yes | No | No |
| Audit logs | Yes (audit device) | CloudTrail | Yes (paid tier) |
At 100 secrets and 2M API calls per month on AWS Secrets Manager, you're looking at roughly $50/month before Lambda rotation costs. Self-hosted Vault with HA adds on-call burden for upgrades, unsealing, and disaster recovery on top of your infra bill. Doppler is predictable flat-rate SaaS.
One often-overlooked cost with Vault is the unsealing ceremony after a restart. Without auto-unseal (via AWS KMS, GCP Cloud KMS, or Azure Key Vault), every Vault restart requires quorum from key holders. At 2 AM during an incident, this is painful.
When to Use Each
Choose Vault when:
- You need dynamic secrets for databases, PKI, or cloud IAM roles
- You operate multi-cloud or on-premises with strict data residency requirements
- You have an infrastructure team that can own upgrades, HA, and disaster recovery
Choose AWS Secrets Manager when:
- Your stack is 100% AWS
- You want automatic RDS password rotation with no code to maintain
- Operational simplicity matters more than cost at your secret count
Choose Doppler when:
- Developer experience is the bottleneck (secrets in
.envfiles, Slack DMs, or worse) - You want to sync secrets across environments, CI/CD, and Kubernetes without writing glue code
- You're a small team and the SaaS operational model is worth the monthly cost
In practice, these tools compose well. Many teams run Vault or Secrets Manager at the infrastructure layer and use Doppler for developer and CI/CD workflows. The environments stay consistent without anyone pasting secrets into config files.
Whatever tool you pick, the fundamentals don't change: least privilege access, audit logging enabled, and a documented rotation schedule. We maintain free security hardening checklists covering secrets management and related controls — useful for validating your setup against concrete criteria.
The Takeaway
Vault is the most powerful option, but power comes with a real operational tax. AWS Secrets Manager is the pragmatic default for AWS-native teams. Doppler is the fastest path to eliminating secrets from .env files without investing in infrastructure.
If you're starting from scratch: Doppler for developer workflows today, with a plan to add Vault or Secrets Manager when dynamic credentials or compliance requirements demand it. Getting secrets out of your codebase matters more than picking the optimal tool on day one.
I run AYI NEDJIMI Consultants, a cybersecurity consulting firm. We publish free security hardening checklists — PDF and Excel.