import/order
Enforce a consistent order of imports, by group and optionally by name
When people add imports wherever there's room, you can't see at a glance what a file depends on, and two branches that add an import in the same spot conflict. This rule sorts imports into groups by where they come from.
The default order is Node.js built-ins, packages, parent folders (../), the same folder (./), then the folder's own index (. or ./). Inside a group any order is fine, unless you set alphabetize.
- The rule checks
importand top-levelconst x = require(). Allrequire()calls go after allimportstatements. import "./app.css"and other imports without a name are skipped, because moving them can change what the code does.bunandbun:testcount as built-ins. With an ESLint config they count as packages, unlesssettings["import/core-modules"]lists them.
--fix moves the imports, unless there's other code between them.
Configure#
Off by default. To turn it on:
[lint.rules]
"import/order" = "error" # or "warn"Every option, set to its default. The ones that are commented out are unset by default.
[lint.rules]
"import/order" = ["error", {
groups = ["builtin", "external", "parent", "sibling", "index"],
# "ignore", "always", "always-and-inside-groups" or "never"
newlines-between = "ignore",
# alphabetize = <object>,
named = false,
pathGroups = [], # list of objects
pathGroupsExcludedImportTypes = ["builtin", "external", "object"],
distinctGroup = true,
sortTypesGroup = false,
# newlines-between-types = <string>,
consolidateIslands = "never", # "inside-groups" or "never"
warnOnUnassignedImports = false,
}]Examples#
Reported:
import { formatDate } from "./format.js";
import express from "express";
import fs from "node:fs";Not reported:
import fs from "node:fs";
import { serve } from "bun";
import express from "express";
import { config } from "../config.js";
import { formatDate } from "./format.js";
import { routes } from "./";Options#
| Option | Default | What it does |
|---|---|---|
groups | ["builtin", "external", "parent", "sibling", "index"] | The order of the groups. A nested array makes several groups count as one. Groups you leave out come last, together. |
newlines-between | "ignore" | "always": one or more empty lines between groups, none inside. "always-and-inside-groups": the same, but empty lines inside a group are fine. "never": no empty lines at all. |
alphabetize | { order: "ignore" } | Sort each group by path. order: "asc" or "desc". caseInsensitive: false by default. orderImportKind: for two imports of the same path, "asc" puts the import type first and "desc" puts it last. |
named | false | Also sort the names inside { }, by alphabetize.order. true, or an object with enabled for all and import, export, require, cjsExports for each kind. Its types key says where inline type names go: "mixed", "types-first" or "types-last". |
pathGroups | [] | Puts paths that match a glob into a group: { pattern, group, position }. position is "before" or "after" the rest of the group. patternOptions takes glob options such as nocase and matchBase. |
pathGroupsExcludedImportTypes | ["builtin", "external", "object"] | Kinds of imports that pathGroups leaves alone. |
distinctGroup | true | For newlines-between, treat a path group with a position as a separate group. |
sortTypesGroup | false | Order the imports in the "type" group by groups too. |
newlines-between-types | same as newlines-between | With sortTypesGroup, the empty lines around and between import type statements. |
consolidateIslands | "never" | "inside-groups", with "always-and-inside-groups": an empty line around each multi-line import, none between single-line imports of a group. |
warnOnUnassignedImports | false | Also check imports without a name. --fix doesn't move them. |
You can put four more groups in groups:
"internal": a path that isn't relative and resolves to a file in your project."unknown": a path that doesn't fit any other group."object":import log = console.login TypeScript."type":import type.
newlines-between#
With "always", this is reported:
import fs from "node:fs";
import express from "express";And this isn't:
import fs from "node:fs";
import express from "express";alphabetize and named#
[lint.rules]
"import/order" = ["error", {
named = true,
alphabetize = { order = "asc", caseInsensitive = true },
}]import { writeFile, readFile } from "node:fs/promises";
import express from "express";
import chalk from "chalk";import { readFile, writeFile } from "node:fs/promises";
import chalk from "chalk";
import express from "express";pathGroups#
Use it for path aliases such as @/, which otherwise count as "unknown":
[lint.rules]
"import/order" = ["error", {
groups = ["builtin", "external", "internal", "parent", "sibling", "index"],
pathGroups = [{ pattern = "@/**", group = "internal" }],
}]import { config } from "../config.js";
import { Button } from "@/components/button";import { Button } from "@/components/button";
import { config } from "../config.js";An alias that looks like a package name, such as @app/button, counts as "external", and pathGroups skips it. Set pathGroupsExcludedImportTypes to ["builtin"] to include it.
The "type" group#
With "type" in groups, every import type goes in that spot, no matter where it imports from:
import type { Server } from "node:http";
import { formatDate } from "./format.ts";import { formatDate } from "./format.ts";
import type { Server } from "node:http";