| | |

ESLint 10 🛡️ The @eslint/js Package — Importing recommended configs

⏱️ Estimated read: 10 min | |

The @eslint/js package is the source of ESLint’s core recommended rule set. It is a separate npm package from eslint itself, and it exports a single object: configs.recommended. That object contains the severity settings for the rules that the ESLint team considers the baseline for every JavaScript project. Importing it into the flat config array is the standard first step in almost every configuration, and it is the replacement for the legacy "extends": "eslint:recommended" string that the old .eslintrc format used.

This chapter covers the package itself, the shape of the recommended object, the import pattern in the flat config array, the defineConfig and extends alternative, and the scoping rule that prevents the recommended config from applying to files it was not meant for.

Key point: js.configs.recommended is an object, not an array. It can be placed directly in the config array, or spread into an object that has a files key to scope it. The defineConfig helper accepts it inside an extends array, which is the cleaner syntax for projects that use the helper.


Why the package is separate from ESLint

The decoupling problem. The core eslint package contains the linter, the CLI, and the rule implementations. The recommended rule set is a configuration decision, not a linter implementation detail. Separating it into @eslint/js allows the recommended set to evolve on its own release cadence and allows projects to depend on the config without depending on a specific ESLint version’s internal structure.

The import problem. In the legacy format, the recommended set was enabled with a string: "extends": "eslint:recommended". The flat config removed the string-based extends for core configs. The @eslint/js package is the explicit replacement: install it, import it, and place the object in the array . The TypeScript-ESLint getting-started guide lists @eslint/js alongside eslint and typescript-eslint as the packages to install for a standard setup .

The scoping problem. The js.configs.recommended object has no files key. When it is placed directly in the array, it applies to every file that ESLint processes. This is the intended behavior for a base config. But when a project has TypeScript files, the core no-unused-vars rule can produce false positives on type-only imports, and the TypeScript-aware replacement from typescript-eslint is needed. The recommended config is still the base; the TypeScript config layers on top of it.


a. The recommended object

The object exported by @eslint/js has a single rules key. The keys of that object are the rule IDs, and the values are the severities. The rules are a curated subset of the full rule list, chosen because they catch likely bugs or enforce universally agreed-upon correctness.

// The shape of js.configs.recommended (simplified)
{
  rules: {
    'no-undef': 'error',
    'no-unused-vars': 'error',
    'no-redeclare': 'error',
    // ... other core rules
  }
}

The exact set changes between major ESLint versions. A rule that is error in one version may be removed or downgraded in the next. This is why the package is versioned separately from eslint: a project can upgrade ESLint without necessarily changing the recommended rule set, and vice versa.


b. The direct import pattern

The most common pattern is to import the package and place the object in the array.

// eslint.config.js
import js from '@eslint/js'

export default [
  js.configs.recommended,
  {
    rules: {
      'no-console': 'warn',
    },
  },
]

The js.configs.recommended object applies to every file. The second object adds a project-specific rule on top. Because the second object is later in the array, its no-console setting takes precedence for any file it matches.

When the recommended config should apply only to a subset of files, it can be spread into an object with a files key.

import js from '@eslint/js'

export default [
  {
    files: ['**/*.js', '**/*.mjs', '**/*.cjs'],
    ...js.configs.recommended,
  },
]

This pattern scopes the recommended rules to JavaScript files only. A TypeScript file in the same project would not receive them, which is the correct behavior when the TypeScript config provides its own equivalent rules.


c. The defineConfig and extends pattern

The defineConfig helper, introduced in ESLint 9.22, provides an extends key that accepts config objects and arrays. The TypeScript-ESLint getting-started guide uses this pattern as the recommended setup.

// eslint.config.mjs
import js from '@eslint/js'
import { defineConfig } from 'eslint/config'

export default defineConfig([
  {
    files: ['**/*.js', '**/*.mjs'],
    extends: [js.configs.recommended],
    rules: {
      'no-console': 'warn',
    },
  },
])

The extends array is flattened by defineConfig, so the js.configs.recommended object is applied to the files matched by the outer files key. This is cleaner than the spread pattern because the scoping and the extension are expressed separately, and the defineConfig wrapper provides type safety in TypeScript .

The @eslint/js package is also used in the legacy-style setup that some tutorials still show, where the recommended config is spread into an object with ignores and other options. The pattern from a Stack Overflow revision spreads eslint.configs.recommended into an object that also sets ignores, which scopes the recommended rules while excluding specific files .


Complete Example Session

// ============================================
// PART 1: THE PACKAGE INSTALLATION
// ============================================
// npm install --save-dev eslint @eslint/js
//
// The @eslint/js package is separate from eslint.
// ============================================
// PART 2: THE DIRECT IMPORT
// ============================================
import js from '@eslint/js'

export default [
  js.configs.recommended,
]

// The recommended rules apply to every file.
// ============================================
// PART 3: ADDING PROJECT RULES
// ============================================
import js from '@eslint/js'

export default [
  js.configs.recommended,
  {
    rules: {
      'no-console': 'warn',
      'eqeqeq': 'error',
    },
  },
]

// The project rules override or extend the recommended set.
// ============================================
// PART 4: SCOPING THE RECOMMENDED CONFIG
// ============================================
import js from '@eslint/js'

export default [
  {
    files: ['**/*.js', '**/*.mjs', '**/*.cjs'],
    ...js.configs.recommended,
  },
]

// The recommended rules apply only to JS files.
// ============================================
// PART 5: THE defineConfig PATTERN
// ============================================
import js from '@eslint/js'
import { defineConfig } from 'eslint/config'

export default defineConfig([
  {
    files: ['**/*.js'],
    extends: [js.configs.recommended],
  },
])

// defineConfig flattens the extends array.
// ============================================
// PART 6: THE TYPESCRIPT COMBINATION
// ============================================
import js from '@eslint/js'
import tseslint from 'typescript-eslint'

export default [
  js.configs.recommended,
  ...tseslint.configs.recommended,
]

// The core rules plus the TypeScript rules.
// ============================================
// PART 7: THE SCOPED TYPESCRIPT COMBINATION
// ============================================
import js from '@eslint/js'
import tseslint from 'typescript-eslint'

export default [
  js.configs.recommended,
  {
    files: ['**/*.ts', '**/*.tsx'],
    extends: [tseslint.configs.recommended],
  },
]

// The TypeScript rules are scoped to TS files.
// ============================================
// PART 8: THE PRETTIER COMBINATION
// ============================================
import js from '@eslint/js'
import eslintConfigPrettier from 'eslint-config-prettier'

export default [
  js.configs.recommended,
  eslintConfigPrettier,
]

// Prettier config turns off formatting rules.
// It must be last.
// ============================================
// PART 9: THE COMPLETE CONFIG
// ============================================
import js from '@eslint/js'
import tseslint from 'typescript-eslint'
import eslintConfigPrettier from 'eslint-config-prettier'

export default [
  { ignores: ['dist/'] },
  js.configs.recommended,
  ...tseslint.configs.recommended,
  eslintConfigPrettier,
]
// ============================================
// PART 10: THE LEGACY EQUIVALENT
// ============================================
// Legacy .eslintrc:
// { "extends": "eslint:recommended" }
//
// Flat config:
// import js from '@eslint/js'
// js.configs.recommended

The ten parts covered the installation, the direct import, adding project rules, scoping the recommended config, the defineConfig pattern, the TypeScript combination, the scoped TypeScript combination, the Prettier combination, the complete config, and the legacy equivalent.


Quick Reference

The package

ItemValue
Package name@eslint/js
Install commandnpm install --save-dev @eslint/js
Default exportjs.configs.recommended
Object shape{ rules: { ... } }
ScopeAll files unless scoped with files

Import patterns

PatternSyntaxScoping
Directjs.configs.recommendedAll files
Spread{ files: [...], ...js.configs.recommended }Matching files
Extendsextends: [js.configs.recommended]Outer files

Common combinations

CombinationOrder
Recommended + project rulesRecommended first
Recommended + TypeScriptRecommended first
Recommended + PrettierPrettier last
Recommended + ignoresIgnores first

The legacy equivalent

LegacyFlat config
"extends": "eslint:recommended"import js from '@eslint/js' + js.configs.recommended

Best Practices

✅ Do This:

// Place the recommended config first
export default [js.configs.recommended, { rules: { ... } }]  // ✅
// Scope the recommended config to JavaScript files
{ files: ['**/*.js'], ...js.configs.recommended }            // ✅
// Use defineConfig for the extends pattern
defineConfig([{ files: ['**/*.js'], extends: [js.configs.recommended] }]) // ✅
// Put eslint-config-prettier last
export default [js.configs.recommended, eslintConfigPrettier] // ✅

❌ Don’t Do This:

// Use the legacy extends string
"extends": "eslint:recommended"                              // ❌
// Assume the recommended config includes TypeScript rules
js.configs.recommended  // no TS rules                        // ❌
// Put Prettier before the recommended config
export default [eslintConfigPrettier, js.configs.recommended] // ❌

Common Pitfalls

PitfallWhy It HappensFix
@eslint/js not foundPackage not installednpm install --save-dev @eslint/js
Recommended rules fire on TS filesConfig not scopedSpread into an object with files
Prettier and ESLint conflictPrettier config not lastPut eslint-config-prettier at the end
Legacy extends string failsFlat config does not support itImport js.configs.recommended
Rules missing after upgradeRecommended set changedCheck the ESLint release notes

Real-World Examples

1. Direct import

import js from '@eslint/js'
export default [js.configs.recommended]

2. With project rules

export default [js.configs.recommended, { rules: { 'no-console': 'warn' } }]

3. Scoped

{ files: ['**/*.js'], ...js.configs.recommended }

4. defineConfig extends

defineConfig([{ files: ['**/*.js'], extends: [js.configs.recommended] }])

5. With TypeScript

export default [js.configs.recommended, ...tseslint.configs.recommended]

6. With Prettier

export default [js.configs.recommended, eslintConfigPrettier]

7. The install command

npm install --save-dev eslint @eslint/js

8. The legacy equivalent

"extends": "eslint:recommended"

9. The object shape

{ rules: { 'no-undef': 'error' } }

10. The complete config

import js from '@eslint/js'
export default [{ ignores: ['dist/'] }, js.configs.recommended]

Visual

The package relationship

┌─────────────────────────────────────────────────────────────┐
│  eslint (the linter)                                         │
│    └── @eslint/js (the recommended config)                   │
│          └── configs.recommended                             │
│                └── { rules: { ... } }                        │
└─────────────────────────────────────────────────────────────┘

The import flow

┌─────────────────────────────────────────────────────────────┐
│  import js from '@eslint/js'                                 │
│       │                                                      │
│       ▼                                                      │
│  js.configs.recommended                                      │
│       │                                                      │
│       ▼                                                      │
│  Placed in the config array                                  │
│       │                                                      │
│       ▼                                                      │
│  Applied to files (all or scoped)                            │
└─────────────────────────────────────────────────────────────┘

The array order

┌─────────────────────────────────────────────────────────────┐
│  [                                                           │
│    { ignores: ['dist/'] },          ← global ignore         │
│    js.configs.recommended,          ← base rules            │
│    ...tseslint.configs.recommended, ← TypeScript rules      │
│    eslintConfigPrettier,            ← disable formatting    │
│    { rules: { 'no-console': 'warn' } } ← project rules      │
│  ]                                                           │
└─────────────────────────────────────────────────────────────┘

The legacy migration

┌─────────────────────────────────────────────────────────────┐
│  Legacy                          Flat config                 │
│                                                              │
│  { "extends": "eslint:recommended" }                         │
│       │                                                      │
│       ▼                                                      │
│  import js from '@eslint/js'                                 │
│  export default [js.configs.recommended]                     │
└─────────────────────────────────────────────────────────────┘

Summary

ItemValue
Package@eslint/js
Importimport js from '@eslint/js'
Config objectjs.configs.recommended
Shape{ rules: { ... } }
PlacementFirst in the array (base config)
ScopingSpread into an object with files
defineConfig patternextends: [js.configs.recommended]
Legacy equivalent"extends": "eslint:recommended"
Prettier ordereslint-config-prettier last

Key takeaways:

  • @eslint/js is the explicit replacement for the legacy eslint:recommended string. The flat config removed the string-based core extends. The package exports the recommended rule set as an object that is placed in the config array .
  • The recommended object applies to all files unless scoped. It has no files key of its own. When a project needs the recommended rules only for JavaScript files, the object is spread into an object with a files pattern.
  • The base config goes first in the array. The recommended config is the foundation. The TypeScript rules, the project-specific rules, and the Prettier disables are layered on top, and the later objects override the earlier ones for the files they match.
  • defineConfig provides an extends key for the cleaner pattern. The TypeScript-ESLint getting-started guide uses extends: [js.configs.recommended] inside a defineConfig call, which scopes the recommended config to the outer files pattern .
  • Prettier’s config must be last. eslint-config-prettier disables the formatting rules that conflict with Prettier. If it is placed before the recommended config, the recommended config re-enables the rules that Prettier just disabled.
  • The package is a separate dependency. Installing eslint alone does not install @eslint/js. The install command for a standard setup includes both, along with typescript-eslint for TypeScript projects .

Remember: The @eslint/js package is the source of the core recommended rules in the flat config. Import it, place js.configs.recommended at the beginning of the array, and layer the project-specific and framework-specific configs on top. Scope it with files if it should not apply to every file. Use defineConfig and extends for the cleaner syntax. And put eslint-config-prettier last so the formatting rules stay disabled.

Was this helpful?


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!