confdrift
v0.1.0 · MIT · Linux, macOS, Windows

Staging works. Production doesn't.

Somewhere between the two, a config key went missing or a timeout lost a zero. confdrift compares your environment configs and tells you what drifted, before the deploy does.

go install github.com/eduardofrafre/confdrift@latest

The problem

Every team with two environments has two configs that quietly disagree.

01

diff compares lines, not settings

Reordered keys, different indentation or a YAML file next to a JSON one, and diff shows noise everywhere and the real change nowhere.

02

The dangerous drift is small

A feature flag that only exists in staging. A timeout of 300 where it should be 3000. A number that turned into a string. Nobody sees it in review.

03

It surfaces as an incident

Drift is invisible until the code that depends on it reaches production. confdrift moves that moment to a pull request.

How it works

Read every file the same way, then compare key by key.

confdrift never compares text. It turns each file into a flat list of key paths and typed values, so formats, ordering and indentation stop mattering, and only real differences are left.

1 · Read

Flatten any format

.env, YAML, JSON and Kubernetes ConfigMaps. The format comes from the file name; nested keys become paths.

# app.yaml
db:
  host: db.internal
  pool:
    max: 20
flattens to
db.host      "db.internal"
db.pool.max  20
2 · Compare

Line up every key

Each key is checked across all the files at once, two environments or ten. A key is the same, changed, or missing somewhere.

keystgprod
RETRY_LIMIT"5""5"same
TIMEOUT_MS"3000""300"changed
NEW_CART"true"-missing
3 · Report

Tell people, and tell CI

A readable report for you, JSON for scripts, credentials redacted, and an exit code a pipeline can act on.

0The files agree
1Drift found
2Bad input: unreadable file, parse error

Try it

Edit the files and watch the report change.

This is the real confdrift engine compiled to WebAssembly, running in your browser. Nothing you type leaves this page. Rename a file to change its format.

Examples

      

Same rules as the CLI: types count, so 5432 and "5432" differ, and keys that look like credentials are compared but printed as <redacted>.

Using it

One command, a few flags, no config file.

Everyday commands

# two environments
confdrift .env.staging .env.production
# or any number of them
confdrift dev.yaml staging.yaml prod.yaml
# only keys missing somewhere
confdrift a.env b.env --keys-only
# skip keys expected to differ
confdrift a.env b.env --ignore 'DATABASE_*'
# for scripts and bots
confdrift a.env b.env --format json

Flags can go before or after the file names. --ignore takes * wildcards and can be repeated.

In CI

# .github/workflows/config-drift.yml
on: pull_request
jobs:
  drift:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-go@v6
      - run: go run github.com/eduardofrafre/confdrift@latest --keys-only deploy/staging.env deploy/production.env

--keys-only is usually what a pipeline wants: values are expected to differ between environments, but a key defined in one and not the other is a bug waiting for a deploy.

Formats

  • dotenv: .env, .env.production, prod.env. Quotes, export, comments and multi-line values are understood. ${VARS} are not expanded: if the reference changed, that is drift.
  • YAML and JSON flatten the same way, to paths like db.pool.max or servers[0], so a YAML file can be compared with a JSON one.
  • Kubernetes ConfigMaps compare by their data keys. Output of helm template or kustomize build works as is: other resources are skipped.

Secrets

Values of keys that look like credentials (*PASSWORD*, *TOKEN*, *SECRET*, *API_KEY* and similar) print as <redacted>, and so do passwords inside URLs. They are still compared, so a rotated secret still shows up as drift. --show-secrets prints them.

exitmeaning
0The files agree
1Drift found
2Bad input: unreadable file, parse error, unknown flag

Install

One static binary. No runtime, no dependencies.

About 3 MB, and it compares a real config in a couple of milliseconds. Pick your platform:

x86-64 shown; for ARM replace amd64 with arm64.

curl -sL https://github.com/eduardofrafre/confdrift/releases/download/v0.1.0/confdrift_0.1.0_linux_amd64.tar.gz | tar xz
sudo mv confdrift_0.1.0_linux_amd64/confdrift /usr/local/bin/
confdrift --version

Open source

Free, MIT licensed, and built in the open.

Found drift confdrift missed, or a format it should read? Open an issue. If it caught something before a deploy did, you can support it by PayPal.