# @adonisjs/eslint-plugin

> ESLint plugin to enforce AdonisJS app specific linting rules

Latest version **2.2.2** (published 2026-02-19) · MIT license · 0 weekly downloads

## Install

```sh
npm install @adonisjs/eslint-plugin
pnpm add @adonisjs/eslint-plugin
yarn add @adonisjs/eslint-plugin
bun add @adonisjs/eslint-plugin
```

## Health

**Score 65/100 (B)** — status: stable.

Positive: has types; esm support; no vulnerabilities; has provenance; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 2.2.2 |
| Published | 2026-02-19 |
| First published | 2023-06-15 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Node | >=20.6.0 |
| Dependencies | 3 |
| Unpacked size | 27.3 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| GitHub stars | 6 |
| Author | Julien Ripouteau |
| Maintainers | romainlanz, virk, julien-r44 |
| Keywords | eslint, adonisjs, eslint-plugin |

## Links

- npm: https://www.npmjs.com/package/@adonisjs/eslint-plugin
- Repository: https://github.com/adonisjs/eslint-plugin-adonisjs
- Homepage: https://github.com/adonisjs/eslint-plugin-adonisjs#readme
- Issues: https://github.com/adonisjs/eslint-plugin-adonisjs/issues
- npm.io page: https://npm.io/package/@adonisjs/eslint-plugin

## Dependencies (3)

- [micromatch](https://npm.io/package/micromatch.md) ^4.0.8
- [read-package-up](https://npm.io/package/read-package-up.md) ^12.0.0
- [@typescript-eslint/utils](https://npm.io/package/@typescript-eslint/utils.md) ^8.56.0

## Alternatives

- [eslint-plugin-sonarjs](https://npm.io/package/eslint-plugin-sonarjs.md) — 2.9M weekly downloads
- [eslint-config-expo](https://npm.io/package/eslint-config-expo.md) — 1.5M weekly downloads
- [@matter/protocol](https://npm.io/package/@matter/protocol.md) — 63.5K weekly downloads
- [@eventcatalog/linter](https://npm.io/package/@eventcatalog/linter.md) — 24.8K weekly downloads
- [@inrupt/eslint-config-base](https://npm.io/package/@inrupt/eslint-config-base.md) — 4.5K weekly downloads

## Recent versions

- 2.2.2 (latest) — 2026-02-19
- 2.0.0-beta.5 (beta) — 2024-08-31
- 2.2.1 — 2026-01-05
- 2.2.0 — 2025-12-20
- 2.1.0 — 2025-12-20
- 2.0.1 — 2025-08-05
- 2.0.0 — 2025-05-25
- 1.3.1 — 2025-05-24
- 2.0.0-beta.4 — 2024-08-31
- 2.0.0-beta.3 — 2024-08-31
- 2.0.0-beta.2 — 2024-08-31
- 2.0.0-beta.1 — 2024-08-31
- 2.0.0-beta.0 — 2024-08-31
- 1.3.0 — 2024-03-07
- 1.2.2 — 2024-02-29
- … 11 more at https://npm.io/package/@adonisjs/eslint-plugin/versions

## README

# @adonisjs/eslint-plugin

> Compatible with ESLint>=9.0 and TypeScript >=5.4

<hr>
<br />

<div align="center">
  <h3>ESLint plugin for AdonisJS applications</h3>
  <p>
    The plugin forces your application to use lazy imports for controllers and event listeners. <strong>Lazy imports are a must when you are using HMR mode in AdonisJS</strong>.
  </p>
</div>

<br />

<div align="center">

[![gh-workflow-image]][gh-workflow-url] [![typescript-image]][typescript-url] [![npm-image]][npm-url] [![license-image]][license-url]

</div>

## Installation

The package comes pre-configured with the [@adonisjs/eslint-config](https://github.com/adonisjs/eslint-config) preset and hence manual installation is not required.

However, you can install and configure it as follows.

```sh
npm i -D @adonisjs/eslint-plugin@beta

# Install peer dependencies
npm i -D eslint@9 typescript typescript-eslint
```

## Usage

After installation, you can register the following as follows. Make sure to also setup the `typescript-eslint` parser in order for the rules to work.

```ts
// eslint.config.js
import adonisJSPlugin from '@adonisjs/eslint-plugin'

export default [
  {
    plugins: {
      '@adonisjs': adonisJSPlugin,
    },
    rules: {
      '@adonisjs/prefer-lazy-controller-import': 'error',
      '@adonisjs/prefer-lazy-listener-import': 'error',
    },
  },
]
```

## `prefer-lazy-controller-import`

> [!IMPORTANT]
> The HMR mode of AdonisJS only works with Lazy loaded controllers

The `@adonisjs/prefer-lazy-controller-import` rule complains when you import a controller using the import expression and assign it to a route. For example:

```ts
import router from '@adonisjs/core/services/router'
// ❌ Error: Replace standard import with lazy controller import
import UsersController from '#controllers/user_controller'

router.get('users', [UsersController, 'index'])
```

The rule is auto fixable, therefore you can apply the fix depending upon the shortcuts provided by your
code editor.

```ts
import router from '@adonisjs/core/services/router'
// ✅ Fixed
const UsersController = () => import('#controllers/user_controller')

router.get('users', [UsersController, 'index'])
```

## `prefer-lazy-listener-import`

> [!IMPORTANT]
> The HMR mode of AdonisJS only works with Lazy loaded event listeners

The `@adonisjs/prefer-lazy-listener-import` rule complains when you import an event listener using the import expression and assign it to an event. For example:

```ts
import emitter from '@adonisjs/core/services/emitter'
// ❌ Error: Replace standard import with lazy controller import
import SendVerificationEmail from '#listeners/send_verification_email'

emitter.on('user:created', [SendVerificationEmail, 'handle'])
```

The rule is auto fixable, therefore you can apply the fix depending upon the shortcuts provided by your
code editor.

```ts
import emitter from '@adonisjs/core/services/emitter'
// ✅ Fixed
const SendVerificationEmail = () => import('#listeners/send_verification_email')

emitter.on('user:created', [SendVerificationEmail, 'handle'])
```

## `prefer-adonisjs-inertia-link`

> [!NOTE]
> This rule is for AdonisJS 7+ projects using `@adonisjs/inertia` v4+.

The `@adonisjs/prefer-adonisjs-inertia-link` rule warns when you import the `Link` component from `@inertiajs/react` or `@inertiajs/vue3` instead of using the typesafe version from `@adonisjs/inertia`.

```ts
// ❌ Warning: Prefer importing Link from @adonisjs/inertia/react for typesafe routing
import { Link } from '@inertiajs/react'
```

```ts
// ✅ Correct
import { Link } from '@adonisjs/inertia/react'
```

## `prefer-adonisjs-inertia-form`

> [!NOTE]
> This rule is for AdonisJS 7+ projects using `@adonisjs/inertia` v4+. You must enable it manually.

The `@adonisjs/prefer-adonisjs-inertia-form` rule warns when you import the `Form` component from `@inertiajs/react` or `@inertiajs/vue3` instead of using the typesafe version from `@adonisjs/inertia`.

```ts
// ❌ Warning: Prefer importing Form from @adonisjs/inertia/react for typesafe routing
import { Form } from '@inertiajs/react'
```

```ts
// ✅ Correct
import { Form } from '@adonisjs/inertia/react'
```

## `no-backend-import-in-frontend`

The `@adonisjs/no-backend-import-in-frontend` rule prevents importing backend code in your frontend files located in the `inertia/` directory.

The rule detects both:

- **Subpath imports** (`#models/user`) - automatically reads your `package.json` imports field
- **Relative imports** (`../../app/models/user`) - checks if the resolved path is outside `inertia/`

```ts
// inertia/pages/users.tsx

// ❌ Error: Importing backend code in frontend files is not allowed
import User from '#models/user'
import { UserService } from '../../app/services/user_service'
```

```ts
// inertia/pages/users.tsx

// ✅ Correct - type-only imports are allowed
import type { User } from '#models/user'
import type { UserService } from '../../app/services/user_service'

// ✅ Correct - imports pointing to inertia/ are allowed
import { Button } from '#components/button' // if #components/* -> ./inertia/components/*
import { utils } from '../utils'
```

### Sharing code between frontend and backend

If you have shared code (e.g., enums, constants, utility types) in your backend that you want to import in your frontend, you can use the `allowed` option to whitelist specific paths:

```ts
// eslint.config.js
export default [
  {
    rules: {
      '@adonisjs/no-backend-import-in-frontend': [
        'error',
        {
          allowed: [
            '#shared/*', // allows #shared/enums, #shared/constants, etc.
            '#shared/**', // allows #shared/utils/helpers (deep nested)
            '#enums', // exact match
          ],
        },
      ],
    },
  },
]
```

The `allowed` option uses [micromatch](https://github.com/micromatch/micromatch) for glob pattern matching.

```ts
// inertia/pages/users.tsx

// ✅ Correct - #shared/* is in the allowed list
import { UserStatus } from '#shared/enums'
```

<div align="center">
  <sub>Built with ❤︎ by <a href="https://github.com/Julien-R44">Julien Ripouteau</a> and <a href="https://github.com/thetutlage">Harminder Virk</a>
</div>

[gh-workflow-image]: https://img.shields.io/github/actions/workflow/status/adonisjs/eslint-plugin-adonisjs/checks.yml?style=for-the-badge
[gh-workflow-url]: https://github.com/adonisjs/eslint-plugin-adonisjs/actions/workflows/checks.yml 'Github action'
[typescript-image]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript
[typescript-url]: "typescript"
[npm-image]: https://img.shields.io/npm/v/@adonisjs/eslint-plugin/latest.svg?style=for-the-badge&logo=npm
[npm-url]: https://www.npmjs.com/package/@adonisjs/eslint-plugin/v/latest 'npm'
[license-url]: LICENSE.md
[license-image]: https://img.shields.io/github/license/adonisjs/eslint-plugin-adonisjs?style=for-the-badge

---
_Source: https://npm.io/package/@adonisjs/eslint-plugin · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
