---
url: /docs/guide/usage/linter/rules/import/extensions.md
---

### What it does

Some file resolve algorithms allow you to omit the file extension within the import source path.
For example the node resolver (which does not yet support ESM/import) can resolve ./foo/bar to the absolute path /User/someone/foo/bar.js because the .js extension is resolved automatically by default in CJS.
Depending on the resolver you can configure more extensions to get resolved automatically.
In order to provide a consistent use of file extensions across your code base, this rule can enforce or disallow the use of certain file extensions.

### Why is this bad?

ESM-based file resolve algorithms (e.g., the one that Vite provides) recommend
specifying the file extension to improve performance. Without extensions, the
bundler must check for various possible file extensions, which can slow down
the build process on large projects. In addition, common ESM environments
(such as browsers and Node.js) typically require fully specified relative imports,
which means extensionless imports are not supported there.

For personal preference and compatibility reasons, the rule also allows configuration
to *disallow* extensions in imports. This is generally not recommended, but it can be
done if preferred.

### Examples

Examples of **incorrect** code for this rule:

The following patterns are considered problems when configuration set to "always":

```js
import foo from "./foo";
import bar from "./bar";
import Component from "./Component";
import foo from "@/foo";
```

The following patterns are considered problems when configuration set to "never":

```js
import foo from "./foo.js";
import bar from "./bar.json";
import Component from "./Component.jsx";
import express from "express/index.js";
```

Examples of **correct** code for this rule:

The following patterns are not considered problems when configuration set to "always":

```js
import foo from "./foo.js";
import bar from "./bar.json";
import Component from "./Component.jsx";
import * as path from "path";
import foo from "@/foo.js";
```

The following patterns are not considered problems when configuration set to "never":

```js
import foo from "./foo";
import bar from "./bar";
import Component from "./Component";
import express from "express/index";
import * as path from "path";
```

**Per-extension configuration examples**:

```js
// Configuration: { "vue": "always", "ts": "never" }
import Component from "./Component.vue"; // ✓ OK - .vue configured as "always"
import utils from "./utils"; // ✓ OK - .ts configured as "never"
import styles from "./styles.css"; // ✓ OK - .css not configured, ignored

// Configuration: ["ignorePackages", { "js": "never", "ts": "never" }]
import foo from "./foo"; // ✓ OK - no extension
import bar from "lodash/fp"; // ✓ OK - package import, ignored (ignorePackages sets this to true)
```

### Differences compared to `eslint-plugin-import`

If you see differences between this rule implementation and the original `eslint-plugin-import`
rule, please note that there are some intentional, inherent differences in the behavior of this
rule and the original.

Oxlint understands and can resolve TypeScript paths out-of-the-box. If your ESLint
configuration did not include `eslint-import-resolver-typescript` or similar, then the original
rule will not have been able to resolve TypeScript paths correctly, and so the behavior
between ESLint and Oxlint may differ. Generally, this means that Oxlint will catch *more*
valid violations than the original rule, though this depends on the specific configuration.

Oxlint is also able to resolve multiple `tsconfig.json` files in a single repo, and so in a
monorepo setup will be more capable with regards to resolving file paths.

## Configuration

### \[0]

type: `"always" | "never" | "ignorePackages"`

Extension rule configuration; Copy to avoid extra indirection.

### \[1]

type: `object`

#### \[1].checkTypeImports

type: `boolean`

default: `false`

Whether to check type imports when enforcing extension rules.

#### \[1].ignorePackages

type: `boolean`

default: `false`

Whether to ignore package imports when enforcing extension rules.

#### \[1].pathGroupOverrides

type: `array`

Path group overrides for bespoke import specifiers.

##### \[1].pathGroupOverrides\[n]

type: `object`

###### \[1].pathGroupOverrides\[n].action

type: `"enforce" | "ignore"`

Action to take when pattern matches.

Action to take for path group overrides.

Determines how import extensions are validated for matching bespoke import specifiers.

###### `"enforce"`

Enforce extension validation for matching imports (require extensions based on config).

###### `"ignore"`

Ignore matching imports entirely (skip all extension validation).

###### \[1].pathGroupOverrides\[n].pattern

type: `string`

Glob pattern to match import specifiers.

#### \[1].pattern

type: `Record<string, string>`

Per-extension rules.

## How to use

## Version

This rule was added in v1.2.0.

## References
