dotenv-diff scans your codebase for environment variable usage and checks it against your env files.
This document focuses on one question: what does the scanner actually check for?
The tool recognises the following patterns:
// Node.js – dot and bracket notation
process.env.MY_KEY
process.env["MY_KEY"]
process.env['MY_KEY']
// Node.js – destructuring
const { MY_KEY } = process.env
const { MY_KEY: alias, OTHER_KEY = "fallback" } = process.env
// Vite / import.meta
import.meta.env.MY_KEY
import.meta.env["MY_KEY"]
import.meta.env['MY_KEY']
// Vite – loadEnv result (e.g. in vite.config.ts)
const env = loadEnv(mode, process.cwd());
env.MY_KEY
const { MY_KEY } = env
// SvelteKit – dynamic (env object)
import { env } from '$env/dynamic/private';
import { env } from '$env/dynamic/public';
env.MY_KEY
const { MY_KEY } = env
const { MY_KEY: alias, OTHER_KEY = "fallback" } = env
// SvelteKit – dynamic with aliased import
import { env as privateEnv } from '$env/dynamic/private';
import { env as publicEnv } from '$env/dynamic/public';
privateEnv.MY_KEY
const { MY_KEY } = privateEnv
// SvelteKit – static (named imports)
import { MY_KEY } from '$env/static/private';
import { MY_KEY } from '$env/static/public';
MY_KEYDocker Compose files are also scanned for shell-style interpolation, so
variables referenced only from a compose file are not reported as unused:
# docker-compose.yml, docker-compose.<env>.yml, compose.yml, compose.<env>.yaml
services:
db:
environment:
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD} # ${VAR}
- POSTGRES_DB=${POSTGRES_DB:-app} # ${VAR:-default}, ${VAR:?err}, ${VAR:+alt}
healthcheck:
test: 'pg_isready --username=$POSTGRES_USER' # bare $VARNote: Only files named like
docker-compose*.yml/.yamlorcompose*.yml/.yamlare treated as Compose files. Other YAML files are not scanned. A doubled$$(Compose's escape for a literal$) is not treated as a reference.
Note: The scanner skips files containing any line over 500 characters, as these are likely minified or bundled — this avoids false positives across all checks below.
Which files are scanned is determined by the file scanning configuration (see configuration and flags).
Variables that are used in code but not defined in the selected env comparison file.
In the standard text output, each missing variable is shown once with the first matching usage location.
Use --json if you need the full list of usages for the same variable.
Variables that are defined in env files but never used in the scanned codebase.
Duplicate variable definitions inside env files (both main env and example env, when available).
Potential secrets and sensitive values, including high-risk patterns. See Security Scanner for a full description of detection techniques and false positive protections.
Potential secrets found in .env.example content. See the Example File Scanning section of the Security Scanner docs.
Framework-aware warnings (for supported frameworks) around unsafe or incorrect env usage patterns. See Framework Warnings.
Variables that do not follow conventional uppercase env naming style.
Variables that appear to use mixed or conflicting naming patterns.
Cases where environment-related values are logged with console.log.
Warnings for environment values that look like expiring tokens/credentials or contain expiration metadata. See Expiration Warnings.
Checks whether .env is properly ignored by .gitignore.
When a variable is reported as missing, dotenv-diff cross-references it against the keys that already exist and suggests the closest match when it looks like a simple spelling mistake.
- Scan mode: a variable used in code but not defined is matched against the keys defined in your env file.
- Compare mode: a key present in the example file but missing from the current file is matched against the extra keys the current file has.
For example, if your code uses DATABASE_URL but your .env defines DATABAS_URL, the missing entry is annotated with → did you mean DATABAS_URL?.
Only close matches are suggested (small edit distance, scaled to key length), and only the single closest key is shown per missing variable. Suggestions are advisory — they do not affect the exit code or the health score. Disable them with --no-suggest.
A final score based on scan findings (missing, unused, duplicates, security warnings, and more).