import/no-duplicates

Disallow importing the same module more than once in a file

fixable

Also called import-x/no-duplicates

Two import lines for one module make it harder to see what a file takes from it, and they're often left over from a merge. One line says it all.

The rule compares the files that the paths resolve to, so ./utils and ./utils.js count as the same module. Each of the imports is reported.

A namespace import (import * as) can't be merged with named imports, so it's allowed next to one. The same goes for import type next to a value import.

--fix merges the imports into the first one.

Configure#

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"import/no-duplicates" = "error" # or "warn"

Every option, set to its default:

bunfig.toml
[lint.rules]
"import/no-duplicates" = ["error", {
  prefer-inline = false,
  considerQueryString = false,
}]

Examples#

example.js2 problems
import { readFile } from "node:fs/promises";
import { join } from "node:path";
import { writeFile } from "node:fs/promises";
utils.js
export const clamp = (n, min, max) => Math.min(Math.max(n, min), max);
export const sum = items => items.reduce((a, b) => a + b, 0);
example.js2 problems
import { clamp } from "./utils";
import { sum } from "./utils.js";
example.jsNo problems
import { readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
example.tsNo problems
import * as React from "react";
import { useState } from "react";
import type { ReactNode } from "react";

Options#

OptionDefaultWhat it does
prefer-inlinefalseReport import type { A } next to import { b } from the same module. --fix merges them as import { type A, b }.
considerQueryStringfalseResolve the part of a path before a ? and compare the part after it as text.
example.tswith { "prefer-inline": true }2 problems
import { useState } from "react";
import type { ReactNode } from "react";
example.tswith { "prefer-inline": true }No problems
import { useState, type ReactNode } from "react";

With considerQueryString, these two paths are the same module:

logo.js
export const width = 64;
export const height = 64;
example.jswith { "considerQueryString": true }2 problems
import { width } from "./logo?inline";
import { height } from "./logo.js?inline";

And these two aren't:

example.jswith { "considerQueryString": true }No problems
import logoUrl from "./logo.svg?url";
import logoText from "./logo.svg?raw";