---
title: "ESLint Config"
description: "Opinionated ESLint flat config for PleaseAI projects — built on @antfu/eslint-config."
---

> Documentation Index
> Fetch the complete documentation index at: https://code-style.pages.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# ESLint Config

`@pleaseai/eslint-config` is an opinionated ESLint flat config built on top of [`@antfu/eslint-config`](https://github.com/antfu/eslint-config). It gives you a single `pleaseai()` function that wires up linting **and formatting** for JS/TS/JSX/Vue/JSON/YAML/Markdown out of the box — no Prettier required.

## Features

- [ESLint flat config](https://eslint.org/docs/latest/use/configure/configuration-files-new) format, composable and future-proof
- Auto-fix for formatting — **use standalone without Prettier**
- TypeScript, JSX, Vue, JSON, YAML, Markdown, TOML, XML, GraphQL, Svelte, Astro, CSS support
- Optional [React, Next.js, Svelte, UnoCSS, Astro, Solid, Angular](/en/eslint-config/frameworks) integrations
- Optional [formatters](#formatters) for CSS / HTML / Markdown via `eslint-plugin-format`
- Includes [`eslint-plugin-package-json`](/en/eslint-config/package-json) configs
- Auto-detects `.gitignore` patterns
- Requires ESLint v10.4.0+

## Installation

```bash
bun add -D @pleaseai/eslint-config eslint
```

```bash
pnpm add -D @pleaseai/eslint-config eslint
```

```bash
npm install -D @pleaseai/eslint-config eslint
```

> **Tip**
>
> Prefer not to set this up by hand? Run `bunx @pleaseai/code-style` — the CLI installs the packages, writes `eslint.config.mjs`, and can also manage a rules block in `AGENTS.md` for AI coding assistants.

## Usage

Create `eslint.config.ts` (or `eslint.config.mjs`) in your project root:

```ts title="eslint.config.ts"
import pleaseai from '@pleaseai/eslint-config'

export default pleaseai()
```

That's it. ESLint will pick it up automatically on the next run.

### With Options

`pleaseai()` accepts the same options as `@antfu/eslint-config`:

```ts title="eslint.config.ts"
import pleaseai from '@pleaseai/eslint-config'

export default pleaseai({
  // Override PleaseAI defaults
  stylistic: {
    indent: 4,
  },

  // Enable framework support
  vue: true,
  react: true,

  // Add ignores
  ignores: [
    '**/fixtures',
  ],
})
```

See [Framework Integrations](/en/eslint-config/frameworks) for the full list of framework flags and their peer dependencies.

### With Additional Configs

Pass additional flat config items as rest arguments — they're merged after the PleaseAI preset:

```ts title="eslint.config.ts"
import pleaseai from '@pleaseai/eslint-config'

export default pleaseai(
  {
    typescript: true,
  },
  {
    files: ['**/*.ts'],
    rules: {
      'no-console': 'warn',
    },
  },
)
```

### Rules Overrides

Every framework integration accepts an `overrides` object so you can tune rules without replacing the whole preset:

```ts title="eslint.config.ts"
import pleaseai from '@pleaseai/eslint-config'

export default pleaseai({
  vue: {
    overrides: {
      'vue/operator-linebreak': ['error', 'before'],
    },
  },
  typescript: {
    overrides: {
      'ts/consistent-type-definitions': ['error', 'interface'],
    },
  },
})
```

For overrides that don't fit a specific integration, pass a second argument with a `rules` object as shown in [With Additional Configs](#with-additional-configs).

> **Note**
>
> Plugin prefixes are renamed for ergonomics — use `ts/*`, `style/*`, `test/*`, `import/*`, etc. See the full mapping in Advanced Usage.

## NPM Scripts

Add the lint commands to your `package.json`:

```json title="package.json"
{
  "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint . --fix"
  }
}
```

Run `npm run lint` to check, or `npm run lint:fix` to auto-fix.

## PleaseAI Defaults

This config wraps `@antfu/eslint-config` with these PleaseAI-specific defaults:

| Option | Value | Note |
| --- | --- | --- |
| `stylistic.indent` | `2` | Two-space indent |
| `stylistic.quotes` | `single` | Single quotes |
| `stylistic.semi` | `false` | No trailing semicolons |
| `typescript` | `true` | Enabled out of the box |
| `gitignore` | `true` | Ignores anything in `.gitignore` |
| `lessOpinionated` | `true` | Disables `antfu/if-newline` and `antfu/curly`, enables `curly: ['error', 'all']` |
| `antfu/top-level-function` | Re-enabled | Prefer `function` declarations at top level |
| `test/prefer-lowercase-title` | Disabled | Test titles can start with any case |

The `lessOpinionated: true` + `curly: ['error', 'all']` combination is the key PleaseAI divergence from antfu's defaults: control-flow statements must always use braces, but antfu's top-level-function preference is still honoured.

## Formatters

ESLint can't natively format `.css`, `.html`, `.xml`, or Markdown frontmatter. Opt in to the `formatters` feature to delegate those files to [`eslint-plugin-format`](https://github.com/antfu/eslint-plugin-format) (which wraps Prettier / dprint) while keeping everything else on pure ESLint:

```ts title="eslint.config.ts"
import pleaseai from '@pleaseai/eslint-config'

export default pleaseai({
  formatters: {
    css: true,
    html: true,
    markdown: 'prettier',
  },
})
```

```bash
bun add -D eslint-plugin-format
```

```bash
pnpm add -D eslint-plugin-format
```

```bash
npm install -D eslint-plugin-format
```

:::note
`formatters` only handles formatting, not linting. For proper CSS **linting** use [Stylelint](https://stylelint.io/) alongside it.
:::

## Type Aware Rules

The strongest TypeScript rules require type information. Opt in by pointing at your `tsconfig.json`:

```ts title="eslint.config.ts"
import pleaseai from '@pleaseai/eslint-config'

export default pleaseai({
  typescript: {
    tsconfigPath: 'tsconfig.json',
  },
})
```

Read more in [Advanced Usage → Type Aware Rules](/en/eslint-config/advanced#type-aware-rules).

## Next Steps

- **[Framework Integrations](/en/eslint-config/frameworks)** — React, Next.js, Vue, Svelte, Astro, Solid, UnoCSS, and Angular — with peer deps.

- **[Advanced Usage](/en/eslint-config/advanced)** — Config Composer, `command` codemods, plugin renaming, versioning policy.

- **[Editor & CI](/en/eslint-config/editor)** — VS Code, Neovim, editor-specific disables, and lint-staged.

- **[Nuxt Integration](/en/eslint-config/nuxt)** — Compose with `@nuxt/eslint` for auto-import-aware linting.

## FAQ

### Prettier?

This config uses ESLint for both linting **and** formatting, so Prettier isn't needed. See [Why I don't use Prettier](https://antfu.me/posts/why-not-prettier) by Anthony Fu for the reasoning.

If you need to format files ESLint can't handle yet (`.css`, `.html`, etc.), use the [formatters](#formatters) option — it wraps Prettier/dprint under the hood without adding a separate tool to your workflow.

### How do I format CSS?

Opt in to the [`formatters`](#formatters) feature. It formats but does not lint — for proper CSS linting pair it with [Stylelint](https://stylelint.io/).

### Curly braces style?

PleaseAI enforces `curly: ['error', 'all']` — always wrap control-flow bodies in braces:

```ts
// ✓ required
function example() {
  if (foo) {
    return true
  }
}

// ✗ rejected
function example() {
  if (foo) return true
}
```

This diverges from antfu's default (which allows brace-less single-line `if`). We made this choice because brace-less bodies interact badly with our other rules like `style/max-statements-per-line` — mixing them produces hard-to-read one-liners.

### Top-level function style?

PleaseAI re-enables `antfu/top-level-function`, so top-level functions should use a `function` declaration rather than an arrow assigned to a `const`:

```ts
// ✓ preferred
export function greet(name: string) {
  return `Hello, ${name}`
}

// ✗ flagged
export const greet = (name: string) => `Hello, ${name}`
```

Arrow functions are still fine inside function bodies, as callbacks, or for inline JSX handlers — the rule only targets top-level declarations. If you disagree, override it:

```ts title="eslint.config.ts"
import pleaseai from '@pleaseai/eslint-config'

export default pleaseai({
  rules: {
    'antfu/top-level-function': 'off',
  },
})
```

Source: https://code-style.pages.dev/en/eslint-config/index.mdx
