Powerful ESLint rules for
package.json
Lint and autofix your package.json files with ESLint, powered by @eslint/json.
This plugin catches real package.json mistakes (invalid names, bad version ranges, broken exports, misplaced @types/*, redundant files entries, and more) and fixes many of them automatically.
npm install --save-dev eslint eslint-package-json
Requires ESLint >=10.4, flat config, and ESM.
Add the recommended config to your eslint.config.js:
import {defineConfig} from 'eslint/config';
import packageJson from 'eslint-package-json';
export default defineConfig({
files: ['**/package.json'],
plugins: {
'package-json': packageJson
},
extends: [
'package-json/recommended'
]
});
This lints every package.json in your project. To tweak individual rules, add them to the same config object:
import {defineConfig} from 'eslint/config';
import packageJson from 'eslint-package-json';
export default defineConfig({
files: ['**/package.json'],
plugins: {
'package-json': packageJson
},
extends: [
'package-json/recommended'
],
rules: {
'package-json/dependency-version-range': [
'error',
{
range: 'caret'
}
]
}
});
If you prefer to wire it up manually instead of using a preset:
import json from '@eslint/json';
import {defineConfig} from 'eslint/config';
import packageJson from 'eslint-package-json';
export default defineConfig({
files: ['**/package.json'],
language: 'json/json',
plugins: {
json,
'package-json': packageJson
},
rules: {
'package-json/valid-fields': 'error'
}
});
recommended — Enables the rules that catch real, uncontroversial mistakes.all — Enables every rule. Useful for discovering rules; not recommended for everyday use.💼 Configurations enabled in.
✅ Set in the recommended configuration.
🔧 Automatically fixable by the --fix CLI option.
💡 Manually fixable by editor suggestions.
| Name | Description | 💼 | 🔧 | 💡 |
|---|---|---|---|---|
| consistent-name-casing | Enforce kebab-case for keys in scripts and bin objects. |
|||
| consistent-path-prefix | Enforce consistent ./ prefix on local path fields. |
✅ | 🔧 | |
| dependency-version-range | Enforce a consistent version range style for dependencies. | ✅ | 💡 | |
| description-format | Enforce formatting of the description field. |
🔧 | ||
| no-absolute-paths | Disallow absolute paths in path fields. | ✅ | ||
| no-backslash-paths | Enforce forward slashes in path fields. | ✅ | 🔧 | |
| no-core-module-dependencies | Disallow dependencies that shadow Node.js built-in modules. | ✅ | 💡 | |
| no-deprecated-fields | Disallow fields and scripts that npm has deprecated. | ✅ | ||
| no-dist-tag-dependencies | Disallow dist-tags as dependency specifiers. | ✅ | ||
| no-duplicate-dependencies | Disallow a dependency listed in multiple dependency groups. | ✅ | 🔧 | |
| no-empty-fields | Disallow empty fields. | ✅ | 💡 | |
| no-exact-peer-dependencies | Disallow exact versions for peer dependencies. | 💡 | ||
| no-exports-trailing-slash | Disallow deprecated trailing-slash folder mappings in exports/imports. |
✅ | 🔧 | |
| no-fallback-export-arrays | Discourage string-target fallback arrays in exports/imports. |
✅ | ||
| no-git-dependencies | Disallow git URLs as dependency specifiers. | |||
| no-http-dependencies | Disallow HTTP URLs as dependency specifiers. | ✅ | ||
| no-install-scripts | Disallow install lifecycle scripts. |
✅ | 💡 | |
| no-invalid-direct-overrides | Disallow npm overrides that conflict with direct dependencies. | ✅ | 🔧 | |
| no-local-dependencies | Disallow local filesystem paths as dependency specifiers. | |||
| no-manual-maintainers | Disallow a manually-set maintainers field. |
✅ | 💡 | |
| no-missing-files | Disallow missing files referenced by package metadata. | |||
| no-nested-exports | Disallow exports and imports in nested package.json files. |
✅ | 💡 | |
| no-orphan-script-hooks | Disallow pre/post script hooks without a corresponding script. |
✅ | ||
| no-orphan-types | Disallow @types/* packages without a corresponding dependency. |
✅ | 💡 | |
| no-overrides-in-published-package | Disallow overrides in packages that can be published. |
✅ | 💡 | |
| no-package-manager-engines | Disallow package manager versions in the engines field. |
✅ | 💡 | |
| no-pre-release-dependencies | Disallow pre-release versions as dependency specifiers. | |||
| no-redundant-files | Disallow redundant entries in the files field. |
✅ | 🔧 | |
| no-redundant-repository-fields | Disallow bugs/homepage values that duplicate what npm infers from repository. |
🔧 | ||
| no-restricted-dependencies | Disallow specific dependencies. | |||
| no-restricted-fields | Disallow specific fields. | 💡 | ||
| no-self-dependency | Disallow a package depending on itself. | ✅ | 💡 | |
| no-typo-fields | Disallow misspelled package.json field names. | ✅ | 🔧 | |
| no-wildcard-dependencies | Disallow wildcard version ranges for dependencies. | ✅ | ||
| no-workspace-protocol-in-published-package | Disallow workspace: dependency specifiers in packages that can be published. |
✅ | ||
| peer-dependencies-as-dev-dependencies | Enforce peer dependencies to also be listed in devDependencies at a compatible version. |
✅ | 💡 | |
| prefer-engines-range | Prefer open-ended >= ranges in the engines field. |
✅ | 💡 | |
| prefer-exports | Prefer an exports-first package interface. |
✅ | ||
| prefer-files-field | Require a files allowlist that covers published entry points. |
✅ | ||
| prefer-https-urls | Prefer https:// URLs in metadata fields. |
✅ | 🔧 | |
| prefer-provenance | Enforce npm provenance via publishConfig.provenance. |
💡 | ||
| prefer-shorthand | Prefer the shorthand string form of fields where possible. | ✅ | 🔧 | |
| prefer-side-effects-field | Recommend declaring the sideEffects field for packages. |
✅ | 💡 | |
| prefer-type-module | Prefer the type field to be module. |
✅ | 💡 | |
| require-bin-shebang | Require bin files to start with the exact #!/usr/bin/env node shebang. |
✅ | ||
| require-default-condition | Require a last default entry in exports/imports conditions objects. |
✅ | ||
| require-engines | Require the engines.node field. |
✅ | ||
| require-entry-point | Require an entry point field. | ✅ | ||
| require-exports-root | Require a usable . root entry in the exports field. |
|||
| require-fields | Require specific fields to be present, always or only for published packages. | ✅ | ||
| require-private-when-workspaces | Require private when workspaces is set. |
✅ | 💡 | |
| require-types-in-exports | Require correctly ordered and module-compatible types in exports. |
✅ | ||
| restrict-fields-when-private | Disallow fields that have no effect when the package is private. | 💡 | ||
| sort-dependencies | Enforce alphabetical ordering of dependencies. | ✅ | 🔧 | |
| sort-files | Enforce a canonical order for entries in the files field. |
✅ | 🔧 | |
| sort-properties | Enforce a canonical order for top-level package.json fields. | ✅ | 🔧 | |
| sort-scripts | Enforce alphabetical ordering of scripts. | 🔧 | ||
| types-in-dev-dependencies | Enforce @types/* packages to be in devDependencies. |
💡 | ||
| valid-fields | Enforce valid values for package.json fields. | ✅ | 🔧 | 💡 |
eslint-plugin-package-json?Both lint package.json through ESLint, and eslint-plugin-package-json is a great project. I built this because I wanted a different design:
dependency-version-range rule with a dependencyTypes option replaces a whole family of no-caret-* / prefer-tilde-* rules. Less to learn, less to configure.@eslint/json. I target ESLint's official JSON language directly, with no parser compatibility layer.npm-package-json-lint?It's a separate CLI with its own config format and no autofix. This plugin lives inside ESLint, so it shares your editor integration, --fix, and flat config.
package.json?package.json must be valid JSON, so it cannot contain comments.
Disable the rule in eslint.config.js instead:
import {defineConfig} from 'eslint/config';
import packageJson from 'eslint-package-json';
export default defineConfig({
files: ['**/package.json'],
plugins: {
'package-json': packageJson
},
extends: [
'package-json/recommended'
],
rules: {
'package-json/no-orphan-types': 'off',
},
});
Use a more specific files pattern when the rule should be disabled for only one package.