eslint-plugin-nextjs-app-router
Version: 
ESLint plugin for Next.js App Router to enforce best practices and catch common mistakes
289 lines (207 loc) ⢠6.77 kB
Markdown
[](https://www.npmjs.com/package/eslint-plugin-nextjs-app-router)
[](https://opensource.org/licenses/MIT)
ESLint plugin for Next.js App Router to enforce best practices and catch common mistakes with Server Components, Client Components, and Server Actions.
- š Detect async components in client components
- āļø Enforce `"use client"` directive when using React hooks
- š Ensure Server Actions return Promises
- šÆ Type-safe and easy to integrate
```bash
bun add -d eslint-plugin-nextjs-app-router
```
or with npm:
```bash
npm install --save-dev eslint-plugin-nextjs-app-router
```
or with yarn:
```bash
yarn add -D eslint-plugin-nextjs-app-router
```
or with pnpm:
```bash
pnpm add -D eslint-plugin-nextjs-app-router
```
Add `nextjs-app-router` to the plugins section of your `.eslintrc` configuration file:
```json
{
  "plugins": ["nextjs-app-router"],
  "rules": {
    "nextjs-app-router/no-async-client-component": "error",
    "nextjs-app-router/use-client-must-exist-with-hooks": "error",
    "nextjs-app-router/use-server-must-return-promise": "error"
  }
}
```
Or use the recommended configuration:
```json
{
  "extends": ["plugin:nextjs-app-router/recommended"]
}
```
Ensures that files with `"use client"` directive do not export async components.
ā **Incorrect:**
```tsx
"use client";
export async function MyComponent() {
  const data = await fetch("/api/data");
  return <div>{data}</div>;
}
```
ā
 **Correct:**
```tsx
"use client";
export function MyComponent() {
  const [data, setData] = useState(null);
  useEffect(() => {
    fetch("/api/data").then(setData);
  }, []);
  return <div>{data}</div>;
}
```
**Why:** Client Components in Next.js App Router cannot be async. They run in the browser and should use hooks like `useEffect` for data fetching.
---
Ensures that files using React hooks have the `"use client"` directive.
ā **Incorrect:**
```tsx
export function MyComponent() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
```
ā
 **Correct:**
```tsx
"use client";
export function MyComponent() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
```
**Why:** React hooks only work in Client Components. Without the `"use client"` directive, the component will be treated as a Server Component, causing runtime errors.
**Note:** By default, this rule only applies to files in `components/`, `features/`, and `hooks/` directories, excluding test and storybook files. You can customize these directories using the rule options (see Configuration section below).
---
### `use-server-must-return-promise`
Ensures that exported functions in files with `"use server"` directive return a Promise or are async.
ā **Incorrect:**
```tsx
"use server";
export const submitForm = (data: FormData) => {
  const name = data.get("name");
  return { success: true };
};
```
ā
 **Correct:**
```tsx
"use server";
export const submitForm = async (data: FormData) => {
  const name = data.get("name");
  await db.insert({ name });
  return { success: true };
};
```
**Why:** Server Actions in Next.js automatically serialize return values, which requires them to return Promises. Non-async functions will be wrapped in a Promise automatically, but making this explicit prevents confusion and potential bugs.
Reference: [Next.js PR 
The plugin provides a recommended configuration that enables all rules with their default settings:
```json
{
  "extends": ["plugin:nextjs-app-router/recommended"]
}
```
You can customize each rule individually:
```json
{
  "plugins": ["nextjs-app-router"],
  "rules": {
    "nextjs-app-router/no-async-client-component": "warn",
    "nextjs-app-router/use-client-must-exist-with-hooks": "error",
    "nextjs-app-router/use-server-must-return-promise": "off"
  }
}
```
You can customize which directories and file patterns this rule applies to:
```json
{
  "plugins": ["nextjs-app-router"],
  "rules": {
    "nextjs-app-router/use-client-must-exist-with-hooks": [
      "error",
      {
        "targetDirs": ["components", "features", "hooks", "ui"],
        "excludePatterns": [".stories", ".test", ".spec"]
      }
    ]
  }
}
```
**Options:**
- `targetDirs` (array of strings): Directory names to target. Default: `["components", "features", "hooks"]`
- `excludePatterns` (array of strings): File patterns to exclude. Default: `[".stories", ".test"]`
**Examples:**
Target all directories:
```json
{
  "rules": {
    "nextjs-app-router/use-client-must-exist-with-hooks": [
      "error",
      {
        "targetDirs": ["*"]
      }
    ]
  }
}
```
Only target `components` and `ui` directories:
```json
{
  "rules": {
    "nextjs-app-router/use-client-must-exist-with-hooks": [
      "error",
      {
        "targetDirs": ["components", "ui"]
      }
    ]
  }
}
```
Exclude additional patterns like `.mock` files:
```json
{
  "rules": {
    "nextjs-app-router/use-client-must-exist-with-hooks": [
      "error",
      {
        "excludePatterns": [".stories", ".test", ".spec", ".mock"]
      }
    ]
  }
}
```
Next.js App Router introduces a new paradigm with Server Components and Client Components. This separation can be confusing, especially for developers new to the App Router. This plugin helps you:
- **Avoid common pitfalls** when working with Server and Client Components
- **Catch errors at lint time** instead of runtime
- **Learn best practices** through clear error messages
- **Maintain consistency** across your codebase
- ESLint 7.0.0 or higher
- Next.js 13+ (App Router)
- Bun 1.2.0+ or Node.js 22.0.0+
Contributions are welcome! Please feel free to submit a Pull Request.
MIT Ā© Masahiro Asahara
- [Next.js App Router Documentation](https://nextjs.org/docs/app)
- [Next.js Server Components](https://nextjs.org/docs/app/building-your-application/rendering/server-components)
- [Next.js Client Components](https://nextjs.org/docs/app/building-your-application/rendering/client-components)
- [Next.js Server Actions](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations)