--- title: "ESLint Plugin" description: "Catch unhead misuse, type-narrowing gaps, and v2-to-v3 migration problems at the source level. Pairs with the runtime ValidatePlugin and the unhead CLI." navigation.title: "ESLint Plugin" --- `@unhead/eslint-plugin` checks `useHead`, `useSeoMeta`, and related calls for problems that TypeScript cannot detect. The recommended config enables 13 rules; the migration config also enables `prefer-define-helpers`. ## Reported problems Type narrowing catches a lot of broken `useHead()` / `useSeoMeta()` calls, but not everything. The ESLint plugin walks tag literals at lint time and surfaces issues like: - Deprecated v2 props (`children`, `hid`, `vmid`, `body: true`) with autofixes - Empty meta content, HTML in titles, relative canonicals - Conflicting robots directives, missing `crossorigin` on font preloads, missing `as` on preloads - Typos in `name` / `property` (Levenshtein-suggested fixes) - Numeric `tagPriority` (suggests the named `'critical'` / `'high'` / `'low'` form) - Twitter handles missing `@`, accessibility-harmful viewport settings These overlap with the runtime [Validate Plugin](/docs/head/guides/plugins/validate) and the `unhead` CLI by design: the same rule IDs flow through static lint, runtime warnings, and CLI reports. ## Setup Install: ::code-block ```bash [Terminal] pnpm add -D @unhead/eslint-plugin ``` :: Wire up the recommended config in flat config: ::code-block ```ts [eslint.config.ts] import { configs } from '@unhead/eslint-plugin' export default [ configs.recommended, ] ``` :: The config registers the `@unhead` plugin namespace and enables every recommended rule. No `files` glob is needed because the rules inspect only calls into the Unhead API. ## The migration config Swap `recommended` for `migration`: ::code-block ```ts [eslint.config.ts] import { configs } from '@unhead/eslint-plugin' export default [ configs.migration, ] ``` :: `configs.migration` enables everything in `recommended` plus `prefer-define-helpers`, which wraps `link` and `script` tag object literals in `defineLink` and `defineScript`. The rule can autofix when the corresponding helper is already imported; otherwise, it offers a suggestion. Combined with the autofixable `no-deprecated-props` rule, this handles much of a v2-to-v3 migration mechanically. > `@unhead/cli` exposes the same rules through `unhead audit` and `unhead migrate`. It uses the oxc parser directly for `.ts`, `.tsx`, `.vue`, and `.svelte` files, without an ESLint parser configuration. ## Rules | Rule | Default | Autofix | What it catches | | --- | --- | --- | --- | | `defer-on-module-script` | `warn` | ✓ | `