# 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 `import` and top-level `const x = require()`. All `require()` calls go after all `import` statements.
- `import "./app.css"` and other imports without a name are skipped, because moving them can change what the code does.
- `bun` and `bun:test` count as built-ins. With an ESLint config they count as packages, unless `settings["import/core-modules"]` lists them.

`--fix` moves the imports, unless there's other code between them.

{/* Generated by src/codegen/lint-rule-docs.ts. Do not edit this section. */}

## Configure

Off by default. To turn it on:

```toml bunfig.toml
[lint.rules]
"import/order" = "error" # or "warn"
```

Every option, set to its default. The ones that are commented out are unset by default.

```toml bunfig.toml
[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,
}]
```

{/* End of the generated section. */}

## Examples

Reported:

{/* bad */}
```js
import { formatDate } from "./format.js";
import express from "express";
import fs from "node:fs";
```

Not reported:

{/* good */}
```js
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.log` in TypeScript.
- `"type"`: `import type`.

### `newlines-between`

With `"always"`, this is reported:

{/* bad {"options": [{"newlines-between": "always"}]} */}
```js
import fs from "node:fs";
import express from "express";
```

And this isn't:

{/* good {"options": [{"newlines-between": "always"}]} */}
```js
import fs from "node:fs";

import express from "express";
```

### `alphabetize` and `named`

```toml bunfig.toml
[lint.rules]
"import/order" = ["error", {
  named = true,
  alphabetize = { order = "asc", caseInsensitive = true },
}]
```

{/* bad {"count": 2, "options": [{"named": true, "alphabetize": {"order": "asc", "caseInsensitive": true}}]} */}
```js
import { writeFile, readFile } from "node:fs/promises";
import express from "express";
import chalk from "chalk";
```

{/* good {"options": [{"named": true, "alphabetize": {"order": "asc", "caseInsensitive": true}}]} */}
```js
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"`:

```toml bunfig.toml
[lint.rules]
"import/order" = ["error", {
  groups = ["builtin", "external", "internal", "parent", "sibling", "index"],
  pathGroups = [{ pattern = "@/**", group = "internal" }],
}]
```

{/* bad {"options": [{"groups": ["builtin", "external", "internal", "parent", "sibling", "index"], "pathGroups": [{"pattern": "@/**", "group": "internal"}]}]} */}
```js
import { config } from "../config.js";
import { Button } from "@/components/button";
```

{/* good {"options": [{"groups": ["builtin", "external", "internal", "parent", "sibling", "index"], "pathGroups": [{"pattern": "@/**", "group": "internal"}]}]} */}
```js
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:

{/* bad {"options": [{"groups": ["builtin", "external", "parent", "sibling", "index", "type"]}]} */}
```ts
import type { Server } from "node:http";
import { formatDate } from "./format.ts";
```

{/* good {"options": [{"groups": ["builtin", "external", "parent", "sibling", "index", "type"]}]} */}
```ts
import { formatDate } from "./format.ts";
import type { Server } from "node:http";
```
