Skip to main content

config-lint

config-lint is a CLI bin shipped by @cogs/config — the framework-agnostic loader behind the canonical layered .env schema used across cogs-family repos. It catches the quote-wrapping mistake at its source: a value copy-pasted verbatim out of a shell-quoted .env file into a deploy provider's env-var box, where the quotes stop being shell syntax and become part of the secret itself.

Unlike @cogs/env-doctor (which inspects env vars already stored on a live Render service — see cogs-env-doctor), config-lint inspects local .env* files before they're ever deployed anywhere.

@cogs/config is a public package: pnpm add @cogs/config installs it, and its bin entry makes config-lint available once the package is linked (e.g. via pnpm exec config-lint in a workspace, or globally if installed globally).

What it does

config-lint resolves and lints exactly the .env* chain envs() would load — .env → .env.local (skipped when NODE_ENV=test) → .env.${ENV} → .env.${ENV}.local — honoring NODE_ENV and ENV from the environment, then runs the package's hygiene checkers (dotenvKeyCheckers, dotenvLineCheckers) against every resolved file.

Usage

config-lint ./apps/web # human output; exit 3 when findings exist
config-lint ./apps/web --json # the Finding[] array, machine-readable
config-lint ./apps/web --fix # rewrite fixable single-line entries in place
config-lint --version # print the installed version and exit

--help output

Real output from config-lint --help (globally linked in this repo):

config-lint — lint an app's layered .env* chain for quote-wrapping mistakes

Catches, at its source, the value that gets copy-pasted verbatim out of a
shell-quoted .env file and into a deploy provider's env-var box — where the
quotes stop being syntax and become part of the secret.

Usage:
config-lint <path-to-app-dir> [--json] [--fix]

Options:
--json Emit the findings array as JSON on stdout instead of human text.
--fix Rewrite fixable single-line entries in place. See the warning below.
-h, --help
--version Print the installed version and exit.

Exit codes:
0 clean — no findings
1 unexpected error
2 usage error
3 findings present

The .env* chain is resolved exactly as `envs()` resolves it, honoring NODE_ENV
and ENV from the environment:
.env → .env.local (skipped when NODE_ENV=test) → .env.${ENV} → .env.${ENV}.local

KNOWN LIMITATIONS, disclosed rather than silently inherited:

--fix applies quoteCharacterFixer and valueWithoutQuotesFixer, which strip and
add quotes GLOBALLY rather than as a matched pair. A value containing an
internal apostrophe or backtick can therefore be corrupted. Fixing those
fixers is out of scope for the change that introduced this bin; review every
--fix diff before committing it.

--fix also applies dotenvKeyFixers to the key (e.g. lowercase keys are
rewritten to uppercase), not just the value fixers described above.

--fix only rewrites entries it can locate on a single physical line. Multiline
quoted values are reported but never rewritten.

trailingWhitespaceChecker is a known-broken checker that was deliberately left
unfixed. It is run for completeness but essentially cannot fire against a
correctly correlated value, and its output should not be trusted.

Example output

Given a .env with a quote-wrapped value:

FOO='abc123'
BAR=plain

Human mode:

$ config-lint .
.env: warning: 'FOO' value ****123' contains quote characters.
config-lint: 1 finding(s)
$ echo $?
3

--json mode:

$ config-lint . --json
[
{
"key": "FOO",
"rule": "quote-character",
"message": "'FOO' value ****123' contains quote characters.",
"file": "/path/to/.env"
}
]

--fix rewrites the fixable entry in place:

$ config-lint . --fix
.env: warning: 'FOO' value ****123' contains quote characters.
config-lint: 1 finding(s)
$ cat .env
FOO=abc123
BAR=plain

Exit codes

CodeMeaning
0Clean — no findings
1Unexpected error
2Usage error
3Findings present

No value is ever printed in full in any output mode — messages mask to the last 4 characters.

Known limitations

These are disclosed rather than silently inherited (verbatim from the package README and --help):

  • --fix can corrupt a value containing an internal quote. quoteCharacterFixer and valueWithoutQuotesFixer strip and add quotes globally rather than as a matched pair. Review every --fix diff before committing it.
  • --fix also applies dotenvKeyFixers to the key (e.g. lowercase keys are rewritten to uppercase), not just the value fixers above.
  • --fix only rewrites single-line entries. Multiline quoted values are reported but never rewritten.
  • trailingWhitespaceChecker is known-broken and was deliberately left unfixed — its output should not be trusted.

Relationship to envs({ lint: true })

The same hygiene checkers config-lint runs are also reachable from application code via envs({ appDirectory, lint: true })lint defaults to false, so hygiene linting is opt-in either way. config-lint is the standalone, CI/pre-commit-friendly way to run the same checks without wiring lint: true into a runtime boot path. See the package README for the full API reference, including correctEnv, envs, and the individual checker/fixer exports.