Skip to main content

conflint

Code-aware configuration linting.
Find every env var, config key and secret your app actually reads, then reconcile it against .env, CI, Docker, Kubernetes and Terraform — before it breaks prod.

pip install conflint · confl check · conflint on PyPI


Why conflint?

Most "works on my machine" disasters are configuration disasters:

  • A teammate deleted a key from .env that your code still requires.
  • The CI workflow never defines DATABASE_URL, so the app crashes at deploy, not at commit.
  • DB_HOST vs DBHOST — the typo that no linter catches because your linter doesn't read your code.
  • A real API key sitting in a committed .env.

.env linters validate a file against a schema you write by hand. conflint reads the actual source code to learn the truth about what your app needs, then reconciles it against every place that value should exist.

Quick start

pip install conflint
# From your project root:
confl check                  # lint the whole project
confl sync                   # regenerate an accurate .env.example
confl explain DB_HOST        # who reads DB_HOST? where is it defined?

Example output:

conflint  checked 42 files (173 config reads, 58 definitions) in 1.24s

app/main.py
  CL001 error: 'DATABASE_URL' is read in code but not defined in any configuration source:12
    hint: Add it to your .env (then run `confl sync` to refresh .env.example)
  CL003 warning: 'DBHOST' is undefined but resembles 'DB_HOST' (distance 1):45
    hint: Did you mean 'DB_HOST'?
docker-compose.yml
  CL004 error: 'POSTGRES_PASSWORD' looks like a committed secret

42 files checked - 2 errors, 1 warning, 0 infos

Commands

Command Purpose
confl check Run all rules and exit 1 if anything reaches your fail level.
confl check --fix Auto-remediate fixable findings (currently: syncs .env.example).
confl sync Regenerate .env.example from code + sources (lossless rewrite).
confl explain KEY Trace one key: every read site and every definition site.
confl rules List all rules with their default severity.
confl init Write a template conflint.toml.
confl version Print the installed version.

Rules

Rule Name Default Meaning
CL001 missing error read in code, defined nowhere
CL002 unused warning defined for real, never read by code
CL003 typo warning undefined name is one edit away from a known one
CL004 secret-leak error high-entropy secret committed in a config source
CL005 drift error documented in .env.example, provided by no real source
CL006 empty-value warning required value defined but empty
CL007 duplicate warning defined twice in one file / conflicting values across sources
CL008 weak-secret warning secret value equals a weak/default placeholder
CL009 undocumented info used or provided, but missing from the example template

What gets scanned

Language Files Recognised reads
Python .py, .pyi (AST) os.environ[...], os.environ.get, os.getenv (+ aliases)
JS/TS .js, .ts, .jsx... process.env, import.meta.env, Bun.env, Deno.env.get, destructuring
Go .go os.Getenv, os.LookupEnv, os.Setenv
Ruby .rb ENV[...], ENV.fetch

Configuration sources (all gitignore-aware in reverse)

Source Finds
dotenv .env, .env.local, .env.example, ...
docker-compose services.*.environment (list & map styles)
github-actions env: maps in .github/workflows/*
kubernetes container env, ConfigMap.data, Secret.data
terraform variable "", .tfvars, environment = {} blocks

Configuration

Config is optional. When you need it, use conflint.toml (or pyproject.toml under [tool.conflint]):

[tool.conflint]
fail-level = "error"              # error | warning | info
require-example = true            # enforce a populated .env.example

enable = { CL003 = "error" }      # raise a rule's severity
disable = ["CL002"]               # turn rules off

ignore-names = ["CI=true", "NODE_ENV=*"]
ignore-paths = ["scripts/**", "vendor/**"]

sources = ["dotenv", "docker-compose", "github-actions", "kubernetes", "terraform"]
scanners = ["python", "javascript"]
reporters = ["text"]

Run confl init to write a commented template.

CI integration

GitHub Actions

- name: Lint configuration
  uses: conflint/conflint@v1
  with:
    reporter: github          # inline PR annotations
    fail-level: error

or with pip directly:

- uses: actions/setup-python@v5
  with: { python-version: "3.12" }
- run: pip install conflint
- run: confl check --github

pre-commit

- repo: https://github.com/conflint/conflint
  rev: v0.1.0
  hooks:
    - id: conflint

Output formats

confl check                       # rich terminal output
confl check --json                # stable JSON schema (v1.0)
confl check --sarif               # SARIF 2.1.0 (CodeQL, Azure Pipelines, GitLab)
confl check --github              # GitHub Actions workflow commands
confl check --report junit        # JUnit XML for Jenkins dashboards
confl check --json --output report.json   # write to a file

Development

git clone https://github.com/conflint/conflint
cd conflint
pip install -e ".[dev]"
pytest
ruff check .
mypy src

License

MIT. See LICENSE.

Similar tools & why conflint is different

Tool What it does What conflint adds
dotenv-linter validates .env against rules reads your code, not a hand-made schema
trufflehog/gitleaks scans git history for secrets live per-key value + drift reconciliation in CI
envcheck-style CLIs compare .env.example to .env cross-source graph: code · .env · CI · k8s · terraform
mypy/ruff static types/lint the configuration layer they ignore

Metadata

Release files for conflint 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for conflint 0.1.1
File Size Uploaded
conflint-0.1.1.tar.gz 55.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for conflint 0.1.1
File Interpreter ABI Platform
conflint-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 116.8 kB

Release files / conflint-0.1.1.tar.gz

Download URL conflint-0.1.1.tar.gz
Size 55.1 kB
Tags Source
SHA-256 checksum
How to use checksums
38d491aafa37e7fc933d34a07ce9991d9c5aa690e60f79bc5bbb196b15d913c9
BLAKE2b-256 checksum
How to use checksums
4ba835ca2f15c73d8be430c6830e90ccbbd5a205a3f970d05e828d2b9d45bc4e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release files / conflint-0.1.1-py3-none-any.whl

Download URL conflint-0.1.1-py3-none-any.whl
Size 61.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2ec3b7b75e71eee9f97dd9c5b38147e0ff839c1946ae5c6245dc1905092ead3c
BLAKE2b-256 checksum
How to use checksums
866f28206fdcdb5d6feacc223c54849de16ab88a83c3efcc5f774061813d30bd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.2

2 release files

This release

0.1.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page