---
title: "Doppler"
description: "Use Doppler for MainSDK secrets - project and config setup, main.yaml, secret references, local testing and swapping."
section: "integrations"
canonical: "https://mainsdk.dev/docs/integrations/doppler"
updated: "2026-10-28"
---

# Doppler

> Use Doppler for MainSDK secrets - project and config setup, main.yaml, secret references, local testing and swapping.

Canonical: https://mainsdk.dev/docs/integrations/doppler · Updated: 2026-10-28

Doppler is a hosted secrets manager and one of the drivers behind [`secrets`](https://mainsdk.dev/docs/interfaces/secrets). Your app reads provider keys from a Doppler config on the server and refers to them in `main.yaml` as `secret:NAME`. Pick it when your team already keeps secrets in Doppler across environments and clouds.

## Interfaces it serves

### Secrets (`secrets`)

- Status: Building for 0.2 · ships as a stable API
- Driver: `doppler` (Doppler)
- Docs: https://mainsdk.dev/docs/interfaces/secrets.md

```yaml
secrets:
  driver: doppler
```

Swap to another provider: `vault`, `aws-secrets-manager`, `gcp-secret-manager`, `azure-key-vault`, `infisical`, `env`, `local`.

## Before you start

1. Create a Doppler project for the app, with a config per environment (development, stage, production).
2. Add each secret under the name you will reference, such as `RESEND_API_KEY`.
3. Create an access token scoped to the one config each environment reads, read-only, and keep it out of code.

## Configure

```yaml title="main.yaml"
secrets:
  driver: doppler               # [TBD] project, config and token settings are not specified yet
email:
  key: secret:RESEND_API_KEY    # suggested name; read from Doppler at startup
```

## Use it

```ts title="app/lib/partner.ts"
import { secrets } from "mainsdk";   // server only

export async function partnerToken() {
  return secrets.get("PARTNER_API_TOKEN");
}
```

## Local development and testing

Use the `local` driver (`.mainsdk/secrets.json`) or `env` in development, or a Doppler development config. In tests, `createTestApp()` from `@mainsdk/testing` uses the in-memory fake, and `chaos.on("secrets", { outage: true })` simulates Doppler being down.

## What MainSDK adds on top

- Server-only access, with values redacted from logs, errors and telemetry.
- The last good value served from memory during an outage (`MAIN-SECRET-0007`), never written to disk.
- A key in code, a committed env file or the browser bundle fails `mainsdk check`.

See [Secrets](https://mainsdk.dev/docs/interfaces/secrets).

## Limits and notes

- The driver comes with the config-secrets spec (phase 1).
- Rotated values are picked up after the driver's cache TTL, with no restart; the TTL is not decided yet.
- `secrets.raw()` returns Doppler's client; `mainsdk check` lists every use.

## Swap to or from it

```yaml title="main.yaml"
secrets:
  driver: doppler   # was vault
```

> **Warning:** Secrets are read in place and MainSDK copies nothing between managers. Create the same names in the new manager before you swap.

## FAQ

**Do I still need `secret:` references with Doppler?** Yes. They keep `main.yaml` free of values and make a later swap a one-line change.

**Can I inject Doppler into env vars instead?** Yes, with the `env` driver, but the `doppler` driver reads values directly and picks up rotation without a restart.

## Next

- [Secrets](https://mainsdk.dev/docs/interfaces/secrets)
- [Infisical](https://mainsdk.dev/docs/integrations/infisical) and [HashiCorp Vault](https://mainsdk.dev/docs/integrations/hashicorp-vault)
