ADR-0008: Doppler for Secrets Management
Status
Accepted - 2025-01-26
Context
TVL Platform requires secure secrets management for sensitive credentials across all environments (development, staging, production):
Secrets to Manage
- Database passwords (PostgreSQL connection strings)
- API keys (Stripe, Hostaway, SendGrid, Linear)
- OAuth secrets (Google OIDC client ID/secret)
- Encryption keys (JWT signing keys, session secrets)
- Third-party tokens (GitHub, Doppler itself)
Business Requirements
- Fast developer onboarding (< 5 minutes to get secrets)
- Team collaboration (shared secrets across team)
- Fast secret rotation (security requirement)
- Audit trail (who accessed what and when)
- SOC 2 Type II compliance readiness
Technical Requirements
- Secure storage (encryption at rest and in transit)
- Automatic synchronization (no manual copying)
- Environment separation (dev, staging, production)
- CLI and UI access
- Integration with CI/CD (GitHub Actions)
- Works with Docker and DevContainers
Constraints
- Small team (2-5 engineers initially)
- Must be cost-effective for MVP (<$50/month)
- Must work on macOS, Linux, Windows
- Cannot commit secrets to git (security risk)
Decision
Doppler for cloud-based secrets management across all environments and team members.
Rationale
- SOC 2 Type II Certified: Meets compliance requirements
- Fast Onboarding: 5 minutes to setup vs. 30 minutes manually
- Automatic Sync: Secrets update when rotated (no manual copying)
- Audit Trail: Track who accessed which secrets when
- Free Tier: 5 users, unlimited secrets (perfect for MVP)
- Team Collaboration: Shared secrets automatically synchronized
- Fast Rotation: Rotate database passwords in 10 minutes vs. 2 hours manually
Alternatives Considered
Alternative 1: .env Files (Manual)
Rejected
Pros:
- Simple (no external dependency)
- Free
- Works offline
Cons:
- Manual copying of secrets (error-prone)
- No audit trail (who accessed what?)
- No rotation strategy (secrets become stale)
- Risk of committing to git (happens accidentally)
- Onboarding takes 30 minutes (find secrets, copy, verify)
- No team collaboration (secrets in Slack/email - insecure)
Decision: Manual process doesn't scale, high security risk.
Alternative 2: AWS Secrets Manager
Rejected
Pros:
- AWS-native (if using AWS)
- Automatic rotation for RDS
- Encryption with KMS
Cons:
- Cost: $0.40/secret/month (~$20/month for 50 secrets)
- AWS lock-in (we use Supabase, not RDS)
- Complex IAM permissions
- No UI (CLI only)
- Requires AWS account setup
- Not suitable for local development
Decision: Too expensive and complex for MVP, AWS-specific.
Alternative 3: HashiCorp Vault
Rejected
Pros:
- Industry standard for large enterprises
- Extremely flexible (dynamic secrets, encryption as a service)
- Open source (self-hosted option)
Cons:
- Operational Overhead: Requires dedicated Vault server, HA setup, backups
- Complexity: Steep learning curve (policies, auth methods, seal/unseal)
- Cost: HashiCorp Cloud Vault ~$50-200/month
- Team Size: Overkill for 2-5 person team
- No UI for secrets management (CLI or API only)
Decision: Too complex for small team, high ops burden.
Alternative 4: GitHub Secrets
Rejected
Pros:
- Free
- Built into GitHub Actions
- Simple setup
Cons:
- Only for CI/CD (not for local development)
- No UI for local access
- No audit trail
- No automatic rotation
- Secrets stored per-repository (not shared across team)
Decision: Solves CI/CD but not local development or team collaboration.
Alternative 5: Infisical
Rejected (for now)
Pros:
- Open source (self-hosted option)
- Similar to Doppler
- Free tier (5 users)
Cons:
- Less mature (founded 2022 vs. Doppler 2018)
- Smaller community
- Not SOC 2 certified (yet)
- Less integrations
Decision: Doppler more mature and SOC 2 certified. Revisit if Infisical matures.
Consequences
Positive
- 
Security - SOC 2 Type II certified (third-party audited)
- Encryption at rest (AES-256) and in transit (TLS 1.3)
- Audit logs (who accessed which secrets when)
- Role-based access control (RBAC)
- No secrets in git (prevented by pre-commit hooks)
 
- 
Developer Experience - 5-minute onboarding (vs. 30 minutes manual)
- Automatic sync (secrets update when rotated)
- CLI and UI access
- Works with Docker and DevContainers
- IDE integration (VS Code extension available)
 
- 
Collaboration - Shared secrets across team (no Slack/email insecure sharing)
- Team members automatically get updated secrets
- Environment separation (dev, staging, production)
 
- 
Rotation - 10-minute rotation (vs. 2 hours manually)
- Update in Doppler → All team members get new secrets automatically
- Example: Rotate database password in 3 steps:
- Update password in Supabase
- Update DATABASE_URLin Doppler
- Done (all environments auto-sync)
 
 
- 
Compliance - SOC 2 Type II certified (required for enterprise customers)
- Audit trail for compliance reports
- Secret versioning (rollback if needed)
 
- 
Cost - Free tier: 5 users, unlimited secrets
- Team tier: $12/user/month (if > 5 users)
- Cost-effective for MVP and growth
 
Negative
- 
Vendor Lock-in - Dependent on Doppler (migration effort if switching)
- Mitigation: Secrets stored in Doppler are exportable (JSON, .env format)
 
- 
External Dependency - Requires internet connection to fetch secrets
- If Doppler down, cannot deploy or onboard
- Mitigation: Doppler has 99.99% uptime SLA, can cache secrets locally
 
- 
Learning Curve - Team must learn Doppler CLI and UI
- Mitigation: Simple CLI, team adapts quickly (~30 minutes)
 
- 
Cost at Scale - $12/user/month if > 5 users
- 20 users = $240/month
- Mitigation: Still cheaper than AWS Secrets Manager or Vault hosting
 
Doppler Setup
1. Install CLI
# macOS
brew install dopplerhq/cli/doppler
# Linux
curl -Ls https://cli.doppler.com/install.sh | sh
# Windows
scoop install doppler
2. Authenticate
# Login to Doppler
doppler login
# Verify authentication
doppler me
3. Setup Project
# Navigate to project directory
cd tvl-platform
# Link to Doppler project
doppler setup
# Select project: tvl-platform
# Select environment: development
4. Download Secrets
# Download to .env.local
doppler secrets download --no-file --format env > .env.local
# Or run commands with secrets injected
doppler run -- pnpm dev
5. CI/CD Integration
# .github/workflows/deploy.yml
name: Deploy
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install Doppler CLI
        uses: dopplerhq/cli-action@v3
      - name: Deploy with secrets
        run: doppler run -- ./deploy.sh
        env:
          DOPPLER_TOKEN: ${{ secrets.DOPPLER_TOKEN }}
Secrets Organization
Project Structure
tvl-platform/
├── development (local dev)
├── staging (pre-production)
└── production (live)
Secret Naming Convention
# Database
DATABASE_URL=postgresql://...
DATABASE_DIRECT_URL=postgresql://... # Supabase direct connection
# Redis
REDIS_URL=redis://...
# APIs
STRIPE_SECRET_KEY=sk_live_...
HOSTAWAY_API_KEY=...
SENDGRID_API_KEY=...
LINEAR_API_KEY=...
# OAuth
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
# Application
JWT_SECRET=...
SESSION_SECRET=...
NEXTAUTH_SECRET=...
# Environment (see ADR-0055 for details)
NODE_ENV=development|test|production  # Build mode (set by framework)
APP_ENV=development|staging|production|preview  # Deployment stage
Developer Workflow
Onboarding New Developer
- Install Doppler CLI (2 minutes)
- Login to Doppler (doppler login) (1 minute)
- Setup project (doppler setup) (1 minute)
- Download secrets (doppler secrets download) (1 minute)
- Start development (pnpm dev) ✅
Total: 5 minutes (vs. 30 minutes manually copying secrets)
Rotating a Secret
- Update secret in service (e.g., rotate Stripe API key in Stripe dashboard)
- Update in Doppler (UI or CLI)
doppler secrets set STRIPE_SECRET_KEY=sk_live_new...
- Done ✅ (all team members and environments auto-sync)
Total: 10 minutes (vs. 2 hours manually updating all environments)
Adding a New Secret
# Add secret to current environment
doppler secrets set NEW_API_KEY=abc123
# Or use UI (doppler.com → project → secrets)
Security Best Practices
1. Never Commit Secrets
# .gitignore
.env
.env.local
.env.*.local
doppler.yaml
2. Use Service Tokens for CI/CD
# Create service token (read-only)
doppler configs tokens create ci-deploy --max-age 90d
# Use in GitHub Secrets
# DOPPLER_TOKEN = <service-token>
3. Rotate Secrets Regularly
- High-Risk: Rotate every 30 days (API keys, database passwords)
- Medium-Risk: Rotate every 90 days (OAuth secrets)
- Low-Risk: Rotate every 180 days (JWT secrets)
4. Use Least Privilege
- Developers: Read-only access to development environment
- DevOps: Write access to staging and production
- CI/CD: Service tokens (read-only, scoped to environment)
Validation Checklist
- Doppler project created (tvl-platform)
- Environments configured (dev, staging, production)
- All secrets stored in Doppler (no .env files in git)
- CLI installed on all developer machines
- CI/CD integrated (GitHub Actions)
- Audit logging enabled
- Service tokens created for CI/CD
- Team members have appropriate access levels
- Secrets rotation schedule documented
- Pre-commit hooks prevent committing .env files