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
| Code | Meaning |
|---|---|
0 | Clean — no findings |
1 | Unexpected error |
2 | Usage error |
3 | Findings 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):
--fixcan corrupt a value containing an internal quote.quoteCharacterFixerandvalueWithoutQuotesFixerstrip and add quotes globally rather than as a matched pair. Review every--fixdiff before committing it.--fixalso appliesdotenvKeyFixersto the key (e.g. lowercase keys are rewritten to uppercase), not just the value fixers above.--fixonly rewrites single-line entries. Multiline quoted values are reported but never rewritten.trailingWhitespaceCheckeris 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.