You're working on your desktop during the day, add a new API key to your .env file, push your code changes, then switch to your laptop in the evening only to discover your app crashes because that environment variable doesn't exist on this machine.
This kept happening to me. I develop on a Windows desktop during the day and a MacBook in the evening. Multiple projects, each with their own secrets. Every new API key meant manually syncing .env files between machines. I kept forgetting.
Doppler fixed this. Secrets live in the cloud and get injected at runtime regardless of which machine I'm on. I deleted my local .env files and haven't thought about syncing since. Here's how I set it up.
The Problem: Environment Variables Across Multiple Machines
If you develop on a single machine, environment variables are simple. Create a .env file, add it to .gitignore, done. But the moment you add a second machine or a teammate, things get complicated:
- Sync drift: Add a variable on one machine, forget to add it on another. Your app works in one place and crashes in another.
- Version confusion: Which machine has the current values? Did I update the API key on my desktop or my laptop?
- Insecure sharing: Copying secrets via Slack, email, or cloud storage creates security vulnerabilities.
- Onboarding friction: New team members need secrets shared manually - often insecurely.
- Cross-platform quirks: Windows and macOS handle environment variables differently, adding another layer of complexity.
I kept losing track of which values were current. I'd develop on my Windows desktop, add a secret, then switch to my MacBook in the evening and spend 10 minutes debugging before realizing I'd forgotten to sync my .env file.
The Solution: Centralized Secrets with Doppler
Doppler is a secrets management platform that centralizes all your environment variables in the cloud. Instead of managing .env files, you store secrets in Doppler and inject them at runtime using their CLI. The key benefits:
- Secrets live in one place, not scattered across machines
- Run
doppler run -- npm run devand all secrets are available to your app - Works identically on Windows, macOS, and Linux
- Separate dev, staging, and production configs
- Base configs that child configs can extend and override
- Free tier includes unlimited projects and secrets for up to 5 team members
I deleted all my local .env files, ran doppler setup in each project, and that was it. When I add a secret on my Windows desktop, it's available on my MacBook. No syncing.
Setting Up Doppler: A Quick Start Guide
1. Install the Doppler CLI
Doppler provides platform-specific installation instructions. Here's how to get started:
# macOS (using Homebrew)
brew install gnupg
brew install dopplerhq/cli/doppler
# Windows (winget is recommended)
winget install doppler.doppler
# Linux (Debian/Ubuntu)
sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
curl -sLf --retry 3 --tlsv1.2 --proto "=https" 'https://packages.doppler.com/public/cli/gpg.DE2A7741A397C129.key' | sudo gpg --dearmor -o /usr/share/keyrings/doppler-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/doppler-archive-keyring.gpg] https://packages.doppler.com/public/cli/deb/debian any-version main" | sudo tee /etc/apt/sources.list.d/doppler-cli.list
sudo apt-get update && sudo apt-get install dopplerAfter installation, authenticate with your Doppler account:
# Login to Doppler (opens browser for authentication)
doppler login2. Create a Project and Add Secrets
In the Doppler dashboard, create a project for your application. Doppler automatically creates three environments: dev, staging, and prod. Add your secrets to the dev config to get started:
# Example secrets for a typical web application
RESEND_API_KEY=re_xxxxxxxxxxxx
RESEND_TO_EMAIL=[email protected]
RESEND_FROM_EMAIL=[email protected]
DATABASE_URL=mongodb://localhost:27017/myapp
REDIS_URL=redis://localhost:63793. Link Your Project Directory
In your project root, run the setup command to link the directory to your Doppler project:
# Navigate to your project
cd ~/projects/my-app
# Link to Doppler project (interactive prompt)
doppler setup
# Select your project and config when promptedThe doppler setup command stores your project and config selection in a global config file (~/.doppler/.doppler.yaml), mapping your project directory to the selected Doppler config. This means no configuration files are added to your project - it just works.
4. Update Your Package Scripts
The key to seamless integration is wrapping your dev scripts with doppler run --. This injects all secrets as environment variables before your command executes:
{
"scripts": {
"dev": "doppler run -- vite",
"server": "doppler run -- node server.js",
"dev:full": "doppler run -- concurrently \"node server.js\" \"vite\"",
"build": "vite build",
"start": "node server.js"
}
}Monorepo Configuration with Config Inheritance
For monorepos, Doppler's config inheritance is useful. You can create a base config that child configs extend, overriding only the variables that differ between packages.
For example, in a monorepo with web, worker, and cron packages, you might structure your configs like this:
- dev: Base development config with shared variables (DATABASE_URL, REDIS_URL, etc.)
- dev_web: Inherits from dev, overrides web-specific variables
- dev_worker: Inherits from dev, overrides worker-specific variables
- dev_cron: Inherits from dev, overrides cron-specific variables
Your package.json scripts then reference the appropriate config for each package:
{
"scripts": {
"dev:web": "doppler run --config dev_web -- pnpm --filter @myapp/web dev",
"dev:worker": "doppler run --config dev_worker -- pnpm --filter @myapp/worker dev",
"dev:cron": "doppler run --config dev_cron -- pnpm --filter @myapp/cron dev",
"dev": "concurrently \"pnpm dev:web\" \"pnpm dev:worker\""
}
}This approach keeps your configuration DRY - shared variables are defined once in the base config, while package-specific overrides are isolated to their respective configs.
Real-World Benefits: My Experience Across Three Projects
I use Doppler in all my active projects: AccessHawk, SPConnector, this portfolio site, and others. Here's what changed:
No More Sync Friction
I stopped thinking about environment variables. When I add an API key on my Windows desktop, it's there when I switch to my MacBook. No copying, no debugging mysterious crashes.
Better Security
Before Doppler, I had .env files that could end up in git history, cloud backups, or get shared insecurely. Now secrets never touch the filesystem. They're injected at runtime from Doppler.
- No
.envfiles to accidentally commit - No secrets stored in plain text on disk
- AI coding assistants (Copilot, Claude Code, Cursor) can't read or leak your secrets because they're not in the codebase
- Audit logs show who accessed or changed secrets
- Rotate secrets without touching code
Simpler Onboarding
My READMEs no longer need sections about copying .env.example files. Setup is two commands:
# One-time setup
doppler login
doppler setup
# Start developing
npm run devTeam-Ready (When Needed)
I work solo, but Doppler's team features mean I'm ready for collaboration without changing anything. New team members run doppler login and doppler setup. No insecure secret sharing.
Pricing: Free for Solo Developers
As of January 2026 the free tier includes:
- Unlimited projects
- Unlimited secrets
- 5 team members
- Core integrations (CLI, SDKs, etc.)
- Community support
For solo developers, this is plenty. I've used the free tier across all my projects without hitting limits. Paid plans add SSO, audit logs, and priority support, but most individual developers won't need them. Doppler updates pricing periodically — check doppler.com/pricing for the current tier.
Migration Tips: From .env Files to Doppler
If you're ready to make the switch, here's a smooth migration path:
- Install and authenticate: Get the Doppler CLI installed on
all your machines and run
doppler login. - Create your project: In the Doppler dashboard, create a project matching your application name.
- Import existing secrets: Copy values from your current
.envfile into Doppler's dev config. - Update package.json: Wrap your dev scripts with
doppler run --. - Test thoroughly: Run your app and verify all environment variables are injected correctly.
- Delete local .env: Once everything works, remove the
.envfile from your machine. - Update documentation: Modify your README to reference
Doppler setup instead of
.env.example. - Repeat on other machines: Run
doppler setupon each machine where you develop.
The whole process takes about 15 minutes per project.
Production Deployments
For production, I use my hosting platform's native environment variables instead of Doppler. Here's why:
- Your production build doesn't need the Doppler CLI installed
- Railway, Vercel, AWS, and other platforms have built-in secret management
- Fewer external dependencies in production is better for security
Doppler does offer production integrations if you want a unified experience. They support Kubernetes secrets, AWS Parameter Store, and direct integrations with many hosting platforms. I use Doppler for local dev and Railway's environment variables for production.
Conclusion
Every time I had to stop and debug a missing environment variable, or manually sync a .env file between machines, I lost momentum on actual work.
Doppler fixed that. I develop on my Windows desktop during the day, switch to my MacBook in the evening, and secrets are there. I don't think about .env files anymore.
If you develop across multiple machines, or want better security for your secrets, Doppler is worth trying. The free tier covers most solo developers.
Key takeaways:
- Doppler centralizes secrets in the cloud, eliminating cross-machine sync issues
- The CLI works identically on Windows, macOS, and Linux
- Config inheritance makes monorepo setups clean and DRY
- Free tier includes unlimited projects and secrets for up to 5 team members
- Migration from .env files takes about 15 minutes per project
- Production deployments can use platform-native environment variables
