MathewTaylor.Doppler.Configuration
0.1.0
dotnet add package MathewTaylor.Doppler.Configuration --version 0.1.0
NuGet\Install-Package MathewTaylor.Doppler.Configuration -Version 0.1.0
<PackageReference Include="MathewTaylor.Doppler.Configuration" Version="0.1.0" />
<PackageVersion Include="MathewTaylor.Doppler.Configuration" Version="0.1.0" />
<PackageReference Include="MathewTaylor.Doppler.Configuration" />
paket add MathewTaylor.Doppler.Configuration --version 0.1.0
#r "nuget: MathewTaylor.Doppler.Configuration, 0.1.0"
#:package MathewTaylor.Doppler.Configuration@0.1.0
#addin nuget:?package=MathewTaylor.Doppler.Configuration&version=0.1.0
#tool nuget:?package=MathewTaylor.Doppler.Configuration&version=0.1.0
Doppler Configuration Provider for .NET
A Doppler secrets provider for Microsoft.Extensions.Configuration. It loads your Doppler secrets at host startup and merges them into IConfiguration, so the rest of your app reads them through the same IConfiguration / IOptions<T> surface as any other source — no Doppler-specific code in your domain.
This is the in-process equivalent of the AddAzureKeyVault(...) / AddSecretsManager(...) providers. The secret backend becomes one swappable Add…() line in Program.cs.
Unofficial. Community-maintained and not affiliated with or endorsed by Doppler, Inc. "Doppler" is a trademark of its respective owner.
Why not just the Doppler CLI?
doppler run --name-transformer dotnet-env -- dotnet …is great and needs no code, but it requires the CLI on every host and makes the CLI the process parent. This provider loads secrets in-process via the Doppler API, which suits all-in-one Docker dev/test boxes and keeps the loading mechanism identical to your other configuration providers.
Packages
| Package | Purpose |
|---|---|
MathewTaylor.Doppler.Configuration |
The provider. Dependency-light, no file IO or crypto. Reference everywhere. |
MathewTaylor.Doppler.Configuration.FileCache |
Optional encrypted cold-start cache. Reference only where you want the fallback (typically dev/test, not production). |
The cache abstraction (IDopplerSecretCache) and the Options.Cache hook live in core; only the concrete FileSecretCache ships in the add-on. A project that doesn't reference the add-on cannot call FileSecretCache — the fallback is excluded at compile time, not just by convention.
Install
dotnet add package MathewTaylor.Doppler.Configuration
# only where you want the cold-start fallback:
dotnet add package MathewTaylor.Doppler.Configuration.FileCache
The id
Doppler.Extensions.Configurationis taken by an abandoned 2022 package, hence theMathewTaylor.prefix.
Quick start
using Doppler.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddDoppler(options =>
{
// Token resolves from DOPPLER_TOKEN if you don't set it here.
options.Optional = builder.Environment.IsDevelopment();
options.ReloadInterval = TimeSpan.FromMinutes(5);
});
var app = builder.Build();
Provide the token via environment variable (recommended):
export DOPPLER_TOKEN="dp.st.dev.xxxxxxxx"
dotnet run
Key mapping
Doppler secret names are UPPER_SNAKE_CASE. Configuration keys are hierarchical, delimited by :. The default KeyMapper maps the __ separator to :, matching .NET's environment-variable convention:
| Doppler secret | Configuration key | Binds to |
|---|---|---|
DATABASE_URL |
DATABASE_URL |
config["DATABASE_URL"] |
SMTP__HOST |
Smtp:Host |
SmtpOptions.Host |
CONNECTIONSTRINGS__DEFAULT |
ConnectionStrings:Default |
config.GetConnectionString("Default") |
Configuration keys are case-insensitive, so casing of the Doppler name doesn't matter for binding. Override options.KeyMapper for a different scheme.
Source ordering
Providers added later win. Add Doppler after appsettings.json and environment variables if Doppler should be authoritative, or before them if local overrides should take precedence:
builder.Configuration
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables()
.AddDoppler(); // Doppler overrides the above
Options
| Option | Default | Description |
|---|---|---|
ServiceToken |
DOPPLER_TOKEN env var |
Doppler service token (dp.st.…). Scoped to one project + config. |
Project |
null |
Only needed for Service Account tokens. |
Config |
null |
Only needed for Service Account tokens. |
Optional |
false |
Swallow load failures and contribute no keys. |
ReloadInterval |
null |
Re-fetch on this interval and trigger change tokens. |
ApiHost |
https://api.doppler.com/ |
Override for gateways or test doubles. |
MaxRetries |
3 |
Extra attempts on 429/5xx/network errors (exponential backoff). |
KeyMapper |
__ → : |
Maps a Doppler name to a configuration key. |
SecretFilter |
null |
Predicate to include/exclude secrets by raw name. |
Cache |
null |
Opt-in encrypted cold-start fallback (see below). |
HttpClient |
null |
Supply your own client (e.g. from IHttpClientFactory). |
HttpMessageHandler |
null |
Custom handler for the internal client (testing). |
All-in-one Docker dev/test boxes
Pass the token into the container and let the app self-hydrate at startup — no CLI in the image:
# docker-compose.yml
services:
app:
build: .
environment:
DOPPLER_TOKEN: ${DOPPLER_TOKEN} # from your shell / .env, never committed
builder.Configuration.AddDoppler(); // reads DOPPLER_TOKEN, fetches at boot
Live reload
Set ReloadInterval and consume via IOptionsMonitor<T>; bound options refresh automatically when a reload detects changes. Background reload failures are swallowed so a transient Doppler outage never crashes a running host.
Resilience and the cold-start cache
There are two distinct outage windows:
- Doppler goes down while the app is running — already covered. Secrets stay in the provider's in-memory store after the first successful load, and background reloads never clear them on failure. No cache needed.
- Cold start while Doppler is unreachable (container restart mid-outage) — the only real gap. With
Optional = falsethe host won't boot; withOptional = trueit boots with no secrets. For this case only, you can opt into an encrypted on-disk snapshot.
In production, failing fast on a cold start is usually safest — let your orchestrator retry. The cache is most useful on local/dev/test boxes. It lives in the separate MathewTaylor.Doppler.Configuration.FileCache package, is opt-in and always encrypted (no plaintext-on-disk default):
var key = Convert.FromHexString(Environment.GetEnvironmentVariable("DOPPLER_CACHE_KEY")!); // 32 bytes
builder.Configuration.AddDoppler(o =>
{
o.Cache = FileSecretCache.WithAesGcm("/var/lib/myapp/doppler.snapshot", key);
});
On every successful fetch the snapshot is refreshed (AES-256-GCM, 0600 perms on Unix). If a startup fetch fails and a valid snapshot exists, the provider loads it (degraded but running) instead of throwing. A tampered or wrong-key snapshot is treated as no cache. Supply your own protect/unprotect delegates via the FileSecretCache constructor (e.g. Windows DPAPI) or implement IDopplerSecretCache for a different store.
Security notes
- Secret values are never logged by this library.
- Treat the service token like any credential — inject it via environment, never commit it.
- Scoped service tokens (read-only, single config) are strongly preferred over personal tokens.
How it works
The provider implements the standard IConfigurationSource / ConfigurationProvider contract. At build time it calls Doppler's GET /v3/configs/config/secrets/download?format=json endpoint with Authorization: Bearer <token>, flattens the returned JSON object, applies the key mapper, and populates the provider's Data. Loading is sync-over-async inside Load() — the same approach the framework's own Azure Key Vault provider uses — and runs once at startup, off the request path.
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Extensions.Configuration (>= 8.0.0)
- System.Net.Http (>= 4.3.4)
- System.Text.Json (>= 8.0.5)
-
net8.0
- Microsoft.Extensions.Configuration (>= 8.0.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on MathewTaylor.Doppler.Configuration:
| Package | Downloads |
|---|---|
|
MathewTaylor.Doppler.Configuration.FileCache
Optional encrypted on-disk cold-start cache for MathewTaylor.Doppler.Configuration. Lets a host fall back to a last-known-good snapshot when Doppler is unreachable at startup. Intended for development and test environments. Reference this package only where you want the fallback (typically not production). Unofficial: community-maintained and not affiliated with or endorsed by Doppler, Inc. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0 | 338 | 6/30/2026 |