# eslint-plugin-import: validating ES module imports before your bundler runs

> eslint-plugin-import checks that every import you write points at a real file and a real export. It is an ESLint plugin for JavaScript and TypeScript teams, and its value and its cost both come from the same place: static resolution of your module graph.

**import-js/eslint-plugin-import** — ESLint plugin with rules that help validate proper imports.

- Repository: https://github.com/import-js/eslint-plugin-import
- Stars: 5,947 · Forks: 1,547
- Language: JavaScript
- License: MIT
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/import-js-eslint-plugin-import

## The problem eslint-plugin-import solves

A bundler will tell you about a broken import eventually, usually at build time, sometimes only at runtime when a lazy chunk fails to load. By then the mistake has been committed, reviewed and possibly merged. The plugin's stated intent is narrower than a bundler's: it lints ES2015+ import and export syntax and, in the README's words, prevents "issues with misspelling of file paths and import names."

That is a lint-time concern, not a build-time one. The rules split into three groups in the README: helpful warnings, module systems, and static analysis. The static analysis group is where the interesting rules live. named checks that a named import corresponds to an actual named export in the target file. default checks that a default export exists when you write a default import. namespace checks that properties you dereference off a namespace import actually exist. export forbids re-exporting the same name. These rules require the plugin to resolve and parse the imported file, which is why it can catch an error that a syntax-only linter cannot.

The audience is teams with enough modules that a human reviewer cannot hold the import graph in their head. It is also for people who want ordering and dependency-direction rules enforced mechanically rather than argued about in review.

## How the plugin resolves and parses your imports

The plugin does not just read the current file. For rules like named and default, it has to find the file the import points at and parse that file's exports. Resolution is delegated to resolvers, and the repository ships a resolvers/ directory alongside a memo-parser/ directory. The memo-parser name hints at the mechanism: parsing the same dependency repeatedly across many linted files would be wasteful, so results are cached.

That architecture explains both the plugin's strength and its main configuration burden. Because resolution is pluggable, the plugin does not assume your project layout. It assumes you will tell it. The README's rules table marks several rules with a keyboard symbol for the typescript configuration, and named is one of them, meaning the TypeScript path is treated as a distinct configuration rather than the default. If your imports go through path aliases, a bundler-specific resolver, or a monorepo layout, the plugin's default resolver will not find the files, and the static analysis rules will either go quiet or report false positives.

There is a second consequence. Rules that require parsing the target file are more expensive than rules that only inspect the current file. no-cycle, which the README describes as forbidding a module from importing a module with a dependency path back to itself, has to walk the graph. On a large repository that walk is the part of your lint run most likely to feel slow, and the plugin offers no way around it other than turning the rule off.

## Installing eslint-plugin-import and running it once

The package is published on npm as eslint-plugin-import, and the repository lists example directories for flat config, legacy config and a v9 setup, so the config format you use determines which example to follow. The package.json files list includes lib, config, docs and index.d.ts, and the main entry is lib/index.js, which is what ESLint loads when the plugin is registered.

With a legacy .eslintrc, the plugin is registered under the plugins key and the recommended set is extended. The README marks export, default, named and namespace as set in the errors configuration and in the recommended configuration, while no-named-as-default and no-named-as-default-member are set to warn.

```json
{
  "plugins": ["import"],
  "extends": ["plugin:import/recommended"]
}
```

Run ESLint over a directory and read the output rather than assuming it is clean. The point of the first run is to see how many existing imports your project already violates, not to fix them.

```bash
npx eslint src
```

Expect the recommended set to be the quiet part. Rules such as no-cycle, no-extraneous-dependencies and no-unused-modules are not enabled by recommended at all, so a clean run under plugin:import/recommended tells you much less than it appears to. Add the rules you actually want one at a time.

## Where eslint-plugin-import gets in the way

The plugin assumes static, resolvable imports. That assumption is the source of most of its friction.

no-dynamic-require forbids require() calls with expressions. If your codebase loads plugins, locales or configuration files by computing a path at runtime, that rule is incompatible with the pattern, and it is not a rule you can half-enable. no-commonjs forbids CommonJS require calls and module.exports or exports.* entirely, and no-amd forbids AMD require and define. These are module-system rules, so they are opt-in, but they exist because the plugin's model is ES modules and everything else is treated as a deviation.

The static analysis rules have a worse failure mode than a false positive: a silent pass. If the resolver cannot find the imported file, the rule has nothing to check. A team that installs the plugin, sees no errors, and concludes their imports are validated may simply have a resolver that is not configured for their alias setup. The README does not document what happens when resolution fails for a given rule, so the honest position is that you should verify the rules fire by introducing a deliberate typo in a branch before trusting them.

There is also a performance cost that scales with repository size. Rules that parse target files and rules that walk the dependency graph both grow with the module count, and the memo-parser exists precisely because that work is repeated otherwise.

## eslint-plugin-import vs eslint-plugin-import-x

The related searches around this project include a direct comparison with eslint-plugin-import-x, and the difference is worth stating plainly. eslint-plugin-import-x is a separate package, not a fork published under this repository, and this repository's README and package.json describe only eslint-plugin-import. Nothing available here documents import-x's internals, so the honest comparison is about packaging and lineage rather than rule behaviour.

What can be said is that this project's release cadence is visible: v2.30.0 in September 2024, v2.31.0 in October 2024, and v2.32.0 in June 2025. The last push to the repository was on 2026-08-23. If you are choosing between the two, the decision should rest on which one supports your ESLint version and your resolver setup, since the rule surface is broadly the same territory: validating imports, ordering them, and forbidding cycles. Neither choice removes the resolver configuration work described above.

A more meaningful alternative for many teams is not another import plugin at all but a type checker. TypeScript's own resolution already catches missing exports and misspelled paths, and it does so with full type information rather than a parse of the target file. If your project is already type-checked in CI, the marginal value of the named and default rules drops considerably, and what remains uniquely useful from this plugin is the ordering and structural rule set: import/order, no-cycle, no-internal-modules, no-relative-packages.

## Maintenance, licence and the upgrade cost

The repository is not archived and the last push was on 2026-08-23. The plugin is licensed under MIT, which is permissive and imposes no copyleft obligation on your project; the LICENSE file is at the repository root and is included in the published package via the files list. That is a statement about the licence text, not legal advice, and if your organisation has licence policy you should route it through whoever owns that policy.

Upgrade cost is the more practical question. The build pipeline in package.json runs Babel over src into lib, and the package declares engines.node as >=4, which is a floor rather than a recommendation. The scripts include separate example test targets for legacy, flat and v9 configurations, which tells you the project treats ESLint's config format migration as something to be tested rather than assumed. When you upgrade ESLint across a major config change, expect to revisit your own config file, not just the plugin version.

The rule set itself is the other upgrade cost. Because recommended enables only a subset, and because several rules are marked deprecated in the README's table with an X symbol, a version bump can change which rules are active under a named configuration. Pin the plugin version in your lockfile and read the changelog before moving.

## Conclusion

Adopt eslint-plugin-import if your codebase is large enough that a typo in an import path can survive review, or if you want import/order and no-cycle enforced rather than discussed. Skip it if you rely on dynamic require() calls, since no-dynamic-require will flag them, or if you are not prepared to configure a resolver and settings for your TypeScript or alias setup. Before enabling it, run the recommended config once and count the errors rather than reading the rule list.

## FAQ

### What is eslint-plugin-import?

It is an ESLint plugin that lints ES2015+ import and export syntax, with rules intended to prevent misspelled file paths and import names. Its rules are grouped into helpful warnings, module systems, and static analysis.

### How do I install eslint-plugin-import?

Install it from npm as a dev dependency alongside ESLint, then register "import" under the plugins key and extend plugin:import/recommended if you are using a legacy config. The repository also ships flat and v9 example directories for the other config formats.

### How do I use eslint-plugin-import?

Add it to your ESLint config, run ESLint over your source directory, and then enable the rules you want beyond the recommended set. Rules such as no-cycle, no-extraneous-dependencies and no-unused-modules are not turned on by the recommended configuration.

### What are the best ESLint plugins?

This plugin is one candidate among many, and its own README does not rank plugins against each other. What the README does document is its rule groups: helpful warnings, module systems, and static analysis, with export, default, named and namespace enabled in the recommended configuration.

### How do I create an ESLint plugin?

That is outside this project's scope. eslint-plugin-import is a consumer of ESLint's plugin API rather than a guide to building one, and its README documents rules and configurations, not plugin authoring.

## Sources

- [import-js/eslint-plugin-import on GitHub](https://github.com/import-js/eslint-plugin-import)
- [Issues](https://github.com/import-js/eslint-plugin-import/issues)
- [License: MIT](https://github.com/import-js/eslint-plugin-import/blob/main/LICENSE)
- [README](https://github.com/import-js/eslint-plugin-import/blob/main/README.md)
- [Releases](https://github.com/import-js/eslint-plugin-import/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/import-js-eslint-plugin-import
