Skip to content

Repository files navigation

Trigger.dev + Doppler env var sync (POC)

Two ways to sync Doppler secrets into a Trigger.dev project, in one example:

  1. A build extension that pulls from Doppler and syncs at deploy time.
  2. A webhook + task that syncs at runtime, the moment a secret changes in Doppler, with no redeploy.

Both paths share one function, fetchSyncableDopplerSecrets, so there's a single place that knows how to talk to Doppler and which keys are syncable. Synced variables are marked as secret in Trigger.dev (redacted in the dashboard/API), and Doppler's three reserved metadata keys (DOPPLER_PROJECT, DOPPLER_CONFIG, DOPPLER_ENVIRONMENT) are filtered out.

This is a proof of concept for discussion, not a supported package.

Approach 1: build extension (deploy-time)

syncDopplerEnvVars wraps the built-in syncEnvVars extension. On every deploy it reads the Doppler config for the environment being deployed and syncs the secrets into Trigger.dev.

import { defineConfig } from "@trigger.dev/sdk";
import { syncDopplerEnvVars } from "./src/extensions/syncDopplerEnvVars";

export default defineConfig({
  project: "<your-project-ref>",
  dirs: ["./src/trigger"],
  maxDuration: 300,
  build: {
    extensions: [
      syncDopplerEnvVars({
        project: "my-app",
        configForEnvironment: (environment) => (environment === "prod" ? "prd" : "dev"),
      }),
    ],
  },
});

Set DOPPLER_TOKEN (a read-only service token) where you deploy, then:

npx trigger.dev@latest deploy

The token is only read on the deploy machine and never ships in the image. Re-sync by deploying again.

Approach 2: webhook + task (runtime, live sync)

Deploy-time sync only picks up changes when you deploy. To reflect a Doppler change immediately, this example listens for Doppler's config.secrets.update webhook and triggers a sync task.

The sync task

sync-doppler-env-vars takes no payload: it downloads and syncs all syncable env vars for its own environment, exactly like the build extension. It uses the in-task envvars.upload call, so it writes to its own project/environment with the run's own credentials (no extra Trigger.dev key needed at runtime, only DOPPLER_TOKEN).

It has concurrencyLimit: 1, so only one sync ever runs at a time.

The Next.js webhook route

app/api/doppler-webhook/route.ts verifies Doppler's X-Doppler-Signature (HMAC-SHA256) and triggers the task. The trigger uses debounce so a burst of webhooks collapses into a single sync of the latest state instead of one run per webhook:

await tasks.trigger<typeof syncDopplerEnvVarsTask>("sync-doppler-env-vars", undefined, {
  debounce: { key: "doppler-sync-<config>", delay: "10s", mode: "trailing", maxDelay: "2m" },
});

trailing means the run fires ~10s after the last webhook in a burst; maxDelay bounds how long a continuous stream of changes can keep pushing it back. Combined with the task's concurrencyLimit: 1, frequent webhooks never pile up runs.

Setup

  1. Set DOPPLER_TOKEN and DOPPLER_PROJECT as env vars in your Trigger.dev project (so the deployed task can download at runtime). Deploy the task with npm run trigger:deploy.

  2. Give the Next.js app a TRIGGER_SECRET_KEY for the environment you want to sync, plus DOPPLER_WEBHOOK_SECRET (the signing secret you'll use on the Doppler webhook). See .env.example.

  3. Run the Next.js app: npm run dev (serves the webhook at POST /api/doppler-webhook).

  4. Expose it publicly. For local development, ngrok:

    ngrok http 3000
  5. In Doppler, create a webhook on your project (Project -> Webhooks) pointing at https://<your-public-url>/api/doppler-webhook, choose the configs to watch, and set the same signing secret as DOPPLER_WEBHOOK_SECRET.

Now change a secret in Doppler. The webhook fires, the route triggers the sync task, and the task pulls the latest secrets from Doppler and updates your Trigger.dev env vars.

Configuration reference

syncDopplerEnvVars(options) (build extension) and fetchSyncableDopplerSecrets(env, source) (shared) take:

Option Description
dopplerToken Doppler token. Defaults to process.env.DOPPLER_TOKEN.
project Doppler project slug. Defaults to process.env.DOPPLER_PROJECT.
config Doppler config to read. Overrides configForEnvironment.
configForEnvironment Maps the Trigger.dev environment (prod/staging/preview/dev) to a Doppler config.
apiUrl Doppler API base URL. Defaults to https://api.doppler.com.
markAsSecret (build extension) Mark synced variables as secret. Defaults to true.

Notes

Marking a variable as secret only takes effect when it is first created. If a variable already exists as non-secret, syncing updates its value but does not flip it to secret.

About

Sync Doppler secrets into Trigger.dev, at deploy time and live via webhook.

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages