Doppler is a secrets management solution that helps you store, sync, and inject secrets into your applications, whether they are running locally or in the cloud. It’s built around a workflow known as SecretOps, which is designed to assist your team in managing sensitive credentials without juggling .env files or hardcoding secrets.
For example, if your frontend team needs encryption keys or connection strings from the backend team to start an application, Doppler can inject those secrets at runtime. The values would never get written to disk or exposed in source files. Doppler also integrates natively with any code that reads from environment variables, including process.env in Node.js, os.environ.get() in Python, or System.getenv() in Java. This means you don’t have to change how your application accesses secrets.
Use it anytime you want to protect secrets and application credentials with scoped access and encryption, avoid copying and pasting secrets between environments, track how secrets are created, pulled, or rotated, and integrate secrets safely into tools like GitHub Actions and AWS. Doppler replaces the need for .env files and helps prevent poor secrets management practices and their associated risks.
In this guide, you’ll learn how to use Doppler to manage secrets across local and cloud environments, from uploading secrets to injecting them into your app and integrating them with CI/CD workflows.
Before jumping into the practical steps, let’s break down the prerequisites into two parts:
Once you have these set up, you're ready to dive into the step-by-step setup.
This tutorial uses a simple Node.js application with a basic form that enables users to sign up with their name and email address.
Behind the scenes, the backend checks for an API_KEY stored in a .env file. If the key is present, the signup succeeds. If it's missing, the signup fails with an error shown in the browser. This scenario demonstrates how Doppler can securely inject secrets into your app at runtime, without relying on .env files or manually exposing secrets.
It also illustrates a typical team workflow: a developer uploading secrets to Doppler and a DevOps engineer injecting those secrets into CI/CD pipelines, eliminating the need for manual key sharing.
In Doppler, configs act like vaults for secrets. They let you group related credentials based on specific use cases or application components. For example, one config might contain API keys, database credentials, and service accounts used by a Kubernetes CRD, while another config might hold secrets required to build a Docker image.
On the other hand, environments represent different stages of your development lifecycle, such as development, staging, and production. Each environment can have its own set of configs, allowing you to isolate and control secrets across stages.
Doppler provides default environments and configs, but you can create new ones as needed.
For this tutorial, we’ll use the default Development environment and its corresponding dev config.
If you haven’t already, clone the demo repo by running:
Then navigate into the project directory and install the dependencies:
Run:
Select:
You'll see a confirmation table in the terminal:
In your project root, create an .env file and paste the text below.
Run:
This will output a confirmation table:
You can also verify the secret has been uploaded by running:
Delete the .env file and run the app:
After starting the app, check your terminal to see which port it’s running on (usually http://localhost:3000). Visit it in your browser and try signing up.
You should get an error message because the app can’t find process.env.API_KEY.
Run:
Visit the same link and sign up again. This time, the secret should be successfully injected from Doppler, and the app will proceed without errors.
Doppler injected the secret at runtime, without requiring a .env file or modifying your code. It naturally populated process.env.API_KEY.
Head over to GitHub and create a new repository named “doppler-secrets-demo”. Once created, copy the HTTPS URL for the repo.
From the root directory of your local project, run the following commands to initialize Git, commit your files, and push the code:
Service tokens in Doppler are scoped credentials that allow external services to fetch or update secrets from a specific project, environment, or config. These tokens can be set to expire and also grant read-only or read/write access, making them suitable for both runtime secrets injection and secrets updates.
In your Doppler dashboard:
Make sure to:
Once created, copy the token.
In your GitHub repo:
The workflow defined in the test.yml file of the demo app uses the DOPPLER_TOKEN you saved earlier to authenticate with Doppler and fetch the API_KEY at runtime.
Under the hood, the Doppler CLI runs as a step in your GitHub Actions workflow. When executed, it authenticates using the DOPPLER_TOKEN and fetches environment variables defined in your Doppler project and config. These secrets are then injected directly into the shell environment, allowing any subsequent commands in the job to access them as native environment variables.
In your GitHub repository:
Once the workflow is complete, expand the “Simulate App Secret Usage” step. You should see the final characters of your API_KEY printed, confirming that Doppler injected the secret into the runtime environment.
This demonstrates that secrets stored in Doppler can be securely integrated into cloud environments, whether through CI/CD pipelines like GitHub Actions or across multiple cloud providers such as AWS, GCP, and others.
Additionally, if you are running a multi-cloud architecture, Doppler can be integrated with native vaults like AWS Secrets Manager to manage different layers of secrets across your environments.
However, it's not enough to simply store secrets and inject them into your environment. Managing sensitive data requires discipline and a structured approach. Fortunately, Doppler provides several features that support best practices. Below are some tips to maintain good secret hygiene over time.
Using a secrets management tool alone doesn’t guarantee your secrets are safe. You need to combine it with the following best practices to reduce unauthorized access, support auditing, and strengthen the long-term security of your workflow.
Secrets should expire before they become liabilities.
Problem: Stale secrets can lead to unauthorized access, privilege creep, or data exposure as teams and services evolve.
Solution: Rotate secrets on a schedule to reduce exposure and limit damage from leaks. Use Doppler’s stale secrets report in the Secret Health dashboard to find secrets that haven’t been rotated, then rotate them using Doppler’s rotated secrets and dynamic secrets features, which let you update credentials either on a schedule or ondemand.
Shared secrets can cause drift and increase risk.
Problem: Duplicating the same API key across services (e.g., mobile, web, backend) leads to inconsistencies and secrets sprawl.
Solution: Use a centralized configuration pattern to keep secrets synced and reduce redundancy. Doppler’s config inheritance helps define shared secrets in a parent config (e.g., production) and inherit them across child configs for each service like mobile-api, web-app, payment-processor.
Keep development and production credentials separate.
Problem: Reusing secrets between development, staging, and production environments introduces the risk of overexposure or accidental data access.
Solution: Use scoped secrets for each environment to maintain clean separation and access control. Doppler’s environment-based architecture allows you to define secrets per environment, allowing modular separation of concerns.
Secrets should be scoped to their purpose, and not everyone needs access to everything.
Problem: Giving all team members access to all secrets and giving secrets too much access increases the risk of misuse or accidental exposure.
Solution: Apply the principle of least privilege using Doppler’s scoped permissions and role-based access controls (RBAC) to define who can view, edit, or rotate secrets. For instance, restrict production secrets to senior engineers while giving read-only access to junior developers.
Don’t let secrets rot unnoticed in your configs.
Problem: Over time, secrets pile up, becoming outdated and unused, yet still exploitable.
Solution: Periodically review and remove stale secrets to keep your system clean and secure. Use Doppler's audit logs and activity history to identify unused secrets and who last accessed them.
Readable names help teams avoid costly mistakes.
Problem: Cryptic or inconsistent secret names lead to confusion and errors during rotation or usage.
Solution: Apply consistent naming patterns based on service and environment. Use prefixes such as MONGO_DB_URI_PROD, STRIPE_API_KEY_DEV, or KUBE_SVC_ACC_STAGING to signal purpose, service, and scope at a glance.
There is no reason to condone the poor handling of sensitive credentials. Managing secrets securely should be a consistent and continuous team-wide practice that becomes a habit.
In this guide, you’ve seen how Doppler helps simplify that process. From storing and syncing secrets to injecting them safely into local and cloud environments, Doppler makes it easier to follow best practices with features like access controls, secret rotation, and change requests.
If protecting your secrets the right way matters to you and your team, now’s the time to start using a dedicated secrets management system. Sign up for Doppler and start putting these practices to work.
Trusted by the world’s best DevOps and security teams. Doppler is the secrets manager developers love.