Configuring ESLint's no-console Rule: A Decision Guide for Dev vs. Production
Decide how to configure ESLint's no-console rule: compare off/warn/error severities and the allow list, then implement a dev-vs-production setup and verify it fails correctly.
19 Apr 2026, 09:22 UTC

Your team keeps shipping console.log calls to production. They pollute logs, occasionally leak request data, and make real errors harder to spot in browser consoles. ESLint's no-console rule can stop this, but the right configuration depends on how much friction your team will tolerate. This guide compares the supported options and shows a working setup that separates development from production behavior.
The decision and its constraints
Decide two things: which console methods are acceptable in committed code, and whether violations should block a build or just nag. Most teams land on the same answer: console.warn and console.error are legitimate for reporting real problems, while console.log, console.info, and console.debug are debugging leftovers that should not ship.
The practical constraint is that the same codebase needs two behaviors. During development you want zero friction; in CI and production builds you want enforcement. The rule supports this through severity levels and an allow list.
Supported options compared
| Configuration | Behavior | Best for | Risk |
|---|---|---|---|
"off" | All console methods permitted | Local development, early prototyping | Debug statements reach production unnoticed |
"warn" | Flags violations, exit code stays 0 | Transition period while cleaning legacy code | Warnings get ignored; no enforcement |
"error" | Flags violations, ESLint exits non-zero | CI pipelines and pre-commit hooks | Blocks builds; frustrating without an escape hatch |
"error" with allow | Errors on all methods except whitelisted ones | Production standard for most teams | Whitelisted methods can still be abused |
Trade-offs worth understanding
Errors enforce, warnings advise. A warn severity keeps the build green, which sounds friendly, but in practice warning output is invisible once a codebase accumulates a few hundred of them. If the goal is preventing production logs, only error combined with a CI lint step actually delivers it.
The allow list is a policy decision, not a technical one. Whitelisting console.warn and console.error acknowledges that some runtime reporting is intentional. Whitelisting console.log defeats the purpose — it is the method most often left behind by accident.
Disabling the rule entirely is the expensive option. Lingering console statements can expose sensitive data (tokens, user objects, request payloads) in browser consoles and server logs. The cleanup cost later exceeds the small friction of enforcement now.
Concrete implementation
A common pattern is a shared base config with an environment-specific override. In a legacy .eslintrc.json setup (ESLint 8 and earlier), that looks like this:
// .eslintrc.json — base, used in development
{
"rules": {
"no-console": "off"
}
}
// .eslintrc.prod.json — used by CI
{
"extends": "./.eslintrc.json",
"rules": {
"no-console": ["error", { "allow": ["warn", "error"] }]
}
}
Run the production config from your CI pipeline (requires Node.js and ESLint installed in the project; run from the repository root):
npx eslint --config .eslintrc.prod.json "src/**/*.{js,ts}"
For flat config (ESLint 9+), the equivalent is an environment-driven eslint.config.js:
const isProd = process.env.NODE_ENV === "production";
export default [
{
rules: {
"no-console": isProd
? ["error", { allow: ["warn", "error"] }]
: "off"
}
}
];
Then set NODE_ENV=production in the CI lint step. This avoids maintaining two config files, at the cost of config behavior depending on an environment variable — document that in your README so contributors are not surprised.
Validate the configuration
Do not trust the config until you have seen it fail correctly. Create a scratch file:
// lint-check.js
console.log("debug leftover");
console.warn("deprecation notice");
console.error("request failed");
Run ESLint against it with the production config. Expected result: exactly one error, reported on the console.log line, and a non-zero exit code (echo $? on Linux/macOS should print 1). If console.warn or console.error also error, the allow array is not being applied — check for a conflicting rule entry later in your config cascade, since the last matching rule wins.
Limitations
The rule only catches direct console usage. Calls routed through a wrapper (window.console.log, aliased references, or a custom logger that internally logs) are not flagged. Treat the rule as a backstop, not a guarantee: pair it with code review, and for sensitive environments consider stripping console calls at build time (for example with a minifier's drop_console option) as a second layer.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.