no-unused-vars

Disallow variables, functions, imports, and parameters that are never used

warn by defaulthas suggestions

A name that's declared and never read is clutter at best. Often it points to a bug. Maybe you computed a value and then used a different name, or a refactor left an import behind.

"Used" means read. A variable that's only assigned to or incremented isn't used, and neither is a function that only calls itself. Anything you export is used.

--fix-suggestions removes the declaration, but only if that can't change what the program does: an unused import, function or class, or a variable set to a plain value. const sent = sendEmail(user); stays, because removing it would also remove the call. So do parameters, names in a destructuring pattern, and the top level of a script that's neither an ES module nor CommonJS, which a web page can use. With an ESLint config file the suggestions are ESLint's.

An unused import always goes. import { setup } from "./polyfills"; is removed as a whole, so the module is no longer loaded. import setup from "./polyfills"; becomes import "./polyfills";, which is how you load a module only for its side effects.

To keep a name that you don't use, start it with _.

This rule is on by default in JavaScript files. In TypeScript files, @typescript-eslint/no-unused-vars is on instead.

Configure#

On by default as a warning. To turn it off:

bunfig.toml
[lint.rules]
"no-unused-vars" = "off" # or "error"

Every option, set to its default:

bunfig.toml
[lint.rules]
"no-unused-vars" = ["warn", {
  vars = "all", # "all" or "local"
  varsIgnorePattern = "^_",
  args = "after-used", # "all", "after-used" or "none"
  argsIgnorePattern = "^_",
  caughtErrors = "all", # "all" or "none"
  caughtErrorsIgnorePattern = "^_",
  destructuredArrayIgnorePattern = "^_",
  ignoreRestSiblings = true,
  ignoreClassWithStaticInitBlock = false,
  ignoreUsingDeclarations = false,
  reportUsedIgnorePattern = false,
}]

Examples#

example.js4 problems
import { readFile, writeFile } from "node:fs/promises";

let saved = 0;

async function save(path, data, options) {
  await writeFile(path, data);
  saved++;
}
example.jsNo problems
import { writeFile } from "node:fs/promises";

let saved = 0;

export async function save(path, data) {
  await writeFile(path, data);
  saved++;
  return saved;
}

An unused parameter is only reported if it comes after the last one that's used, because you can't remove the others:

example.jsNo problems
export const doubled = items.map((item, index) => index * 2);

A name that starts with _ is unused on purpose:

example.jsNo problems
export function onMessage(_event) {}

const [_first, second] = items;
send(second);

A component that only appears in JSX is used:

example.jsxNo problems
import Button from "./button";

export const App = () => <Button />;

Options#

bunfig.toml
[lint.rules]
no-unused-vars = ["error", { args = "all" }]

An option you don't set keeps its default. With an ESLint config the defaults are ESLint's: no patterns, and ignoreRestSiblings is false.

OptionDefaultWhat it does
vars"all""local" skips globals: the names in /* global */ comments and the top-level variables of a classic script. The top level of a module or a CommonJS file is still checked.
varsIgnorePattern"^_"Regular expression for variable names that may be unused.
args"after-used""all" reports every unused parameter, "none" reports none.
argsIgnorePattern"^_"Like varsIgnorePattern, for parameters.
caughtErrors"all""none" allows an unused error in catch (error).
caughtErrorsIgnorePattern"^_"Like varsIgnorePattern, for the catch parameter.
destructuredArrayIgnorePattern"^_"Like varsIgnorePattern, for names in const [a, b] = list.
ignoreRestSiblingstrueAllow unused names next to a ...rest in object destructuring.
ignoreClassWithStaticInitBlockfalseAllow an unused class that has a static {} block, which runs anyway.
ignoreUsingDeclarationsfalseAllow unused using and await using variables, which are disposed of anyway.
reportUsedIgnorePatternfalseReport a name that matches one of the patterns and is used.

You can pass a string instead of the object, "all" or "local", to set vars.

With { "args": "all" }, an unused parameter before a used one is reported too:

example.jswith { "args": "all" }1 problem
export const doubled = items.map((item, index) => index * 2);

The "^_" patterns still apply, so _item isn't:

example.jswith { "args": "all" }No problems
export const doubled = items.map((_item, index) => index * 2);

ignoreRestSiblings is for taking properties out of an object:

example.jsNo problems
const { password, ...publicUser } = user;
send(publicUser);
example.jswith { "ignoreRestSiblings": false }1 problem
const { password, ...publicUser } = user;
send(publicUser);
example.jswith { "varsIgnorePattern": "^_", "reportUsedIgnorePattern": true }1 problem
const _timeout = 500;
wait(_timeout);

By default, a name in a /* global */ comment that the file never uses is reported too:

example.js1 problem
/* global analytics */

console.log("ready");
example.jswith "local"No problems
/* global analytics */

console.log("ready");