- 技術 💻
ESLint flat config設定|v10対応の完成形コピペ集
ESLintのflat configとは、プロジェクト直下の eslint.config.js に、設定オブジェクトの配列をJavaScriptで書く設定方式です。 ESLint 9で標準になり、2026年2月リリースのESLint 10では従来の .eslintrc.* 形式が使えなくなりました。 現在ESLintを使うなら、flat configが唯一の設定方法です。
この記事では、ESLint 10.11.0 + typescript-eslint 8.71.0 で、JavaScript・TypeScript・React・Vue・Node.js・Prettier併用の用途別の完成形 eslint.config.js を載せています。すべて npx eslint を実行し、検出結果、--fix の前後、.eslintrc からの自動移行の結果を掲載しました。ignore が効かないケースなどのエラーも再現しています。
用途別の早見表
| 用途 | 追加で入れるパッケージ | 設定のポイント |
|---|---|---|
| JavaScript(ブラウザ) | eslint @eslint/js globals |
extends: [js.configs.recommended]、globals.browser |
| TypeScript | typescript-eslint typescript |
tseslint.configs.recommended |
| TypeScript(型情報つき) | 同上 | recommendedTypeChecked + parserOptions.projectService: true |
| React | @eslint-react/eslint-plugin |
eslintReact.configs['recommended-typescript'] |
| Vue | eslint-plugin-vue |
pluginVue.configs['flat/recommended'] + parserOptions.parser |
| Node.js(ESM) | eslint-plugin-n |
nodePlugin.configs['flat/recommended-module']、globals.nodeBuiltin |
| Prettier と併用 | eslint-config-prettier prettier |
eslint-config-prettier/flat を配列の最後に置く |
| ファイルを除外 | (なし) | globalIgnores(['dist/']) |
| 設定の中身を確認 | @eslint/config-inspector |
npx eslint --inspect-config |
| eslintrc から移行 | @eslint/migrate-config |
npx @eslint/migrate-config .eslintrc.json |
設定オブジェクトのキー一覧
| キー | 役割 | 例 |
|---|---|---|
files |
対象ファイルのglob | ['**/*.{ts,tsx}'] |
ignores |
このオブジェクトから除外(単独なら全体から除外) | ['**/*.test.ts'] |
extends |
他の設定を継承(defineConfig 内で使える) |
[js.configs.recommended] |
plugins |
プラグインを名前つきで登録 | { react: reactPlugin } |
rules |
ルールの有効・無効 | { eqeqeq: ['error', 'always'] } |
languageOptions.globals |
グローバル変数 | globals.browser |
languageOptions.parserOptions |
パーサーの設定 | { projectService: true } |
languageOptions.sourceType |
module / commonjs / script |
既定は .js が module、.cjs が commonjs |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「ESLint flat config設定|v10対応の完成形コピペ集」
検証環境とESLint 10の主な変更点
| パッケージ | バージョン |
|---|---|
| Node.js | 22.22.2 |
| eslint | 10.11.0 |
| typescript-eslint | 8.71.0 |
| typescript | 6.0.3(理由は後述) |
| eslint-plugin-vue | 10.11.1 |
| @eslint-react/eslint-plugin | 5.22.1 |
公式の移行ガイド(Migrate to v10.x)で確認した、設定に関わる変更です。
| 変更 | 内容 |
|---|---|
| eslintrc 形式の削除 | .eslintrc.* は読み込まれない |
| 設定ファイルの探し方 | リントするファイルのディレクトリから上に向かって eslint.config.* を探す |
/* eslint-env */ コメント |
エラーとして報告される |
| 必要な Node.js | v20.19.0以上 / v22.13.0以上 / v24以上 |
eslint:recommended |
no-unassigned-vars no-useless-assignment preserve-caught-error が追加 |
TypeScript 7(latest は 7.0.2)について:typescript-eslint 8.71.0 の peerDependencies は typescript: '>=4.8.4 <6.1.0' で、TypeScript 7.0.2 と一緒に入れると npm error ERESOLVE unable to resolve dependency tree(Found: typescript@7.0.2)になりました。
2026年9月時点では、ESLintと組み合わせるなら typescript@6.0.x を入れると依存関係が解決します(この記事の検証も 6.0.3 です)。対応状況は typescript-eslint のリリースノートで確認してください。
JavaScript の完成形
npm i -D eslint @eslint/js globals
// eslint.config.js(package.json に "type": "module")
import { defineConfig, globalIgnores } from 'eslint/config'
import js from '@eslint/js'
import globals from 'globals'
export default defineConfig([
globalIgnores(['dist/']),
{
files: ['**/*.{js,mjs,cjs}'],
plugins: { js },
extends: ['js/recommended'],
languageOptions: { globals: globals.browser },
rules: {
'prefer-const': 'error',
'no-var': 'error',
eqeqeq: ['error', 'always'],
},
},
])
defineConfig と globalIgnores は eslint/config から読み込みます。 defineConfig を使うと extends が書け、配列の入れ子も平らにしてくれます。'js/recommended' は plugins に登録した js の recommended 設定を指す文字列で、js.configs.recommended と直接書いても同じです。
実行ログ
リント対象のコードです。
// src/order.js
var total = 0
const unused = 1
export function addItem(items, item) {
if (item.qty == 0) {
return items
}
let result = [...items, item]
return result
}
console.log(undeclaredVar)
$ npx eslint .
src/order.js
1:1 error Unexpected var, use let or const instead no-var
1:5 error 'total' is assigned a value but never used no-unused-vars
2:7 error 'unused' is assigned a value but never used no-unused-vars
5:16 error Expected '===' and instead saw '==' eqeqeq
8:7 error 'result' is never reassigned. Use 'const' instead prefer-const
12:13 error 'undeclaredVar' is not defined no-undef
✖ 6 problems (6 errors, 0 warnings)
2 errors and 0 warnings potentially fixable with the `--fix` option.
(ファイルパスは短く表記しています。以降も同様)
--fix の前後
npx eslint . --fix で自動修正された差分です。
- var total = 0
+ const total = 0
...
- let result = [...items, item]
+ const result = [...items, item]
自動修正されたのは no-var と prefer-const の2件で、残る4件は人が判断して直します。
TypeScript の完成形(型情報つき)
npm i -D eslint @eslint/js globals typescript-eslint typescript@6
// eslint.config.js
import { defineConfig, globalIgnores } from 'eslint/config'
import js from '@eslint/js'
import tseslint from 'typescript-eslint'
import globals from 'globals'
export default defineConfig([
globalIgnores(['dist/']),
{
files: ['**/*.{js,mjs,cjs,ts,mts,cts}'],
extends: [js.configs.recommended, tseslint.configs.recommendedTypeChecked],
languageOptions: {
globals: globals.browser,
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
{
// 型情報を使うルールを JS ファイルでは無効にする
files: ['**/*.{js,mjs,cjs}'],
extends: [tseslint.configs.disableTypeChecked],
},
])
projectService: true は、各ファイルに対応する tsconfig.json を自動で見つけて型情報を使う設定です。以前の project: './tsconfig.json' より設定が簡単で、typescript-eslint が推奨しています。型情報が不要なら tseslint.configs.recommended にして parserOptions を省けます(速く動きます)。
実行ログ
// src/task.ts
type Task = { id: number; title: string; done: boolean }
export async function fetchTask(id: number): Promise<Task> {
const res = await fetch(`/api/tasks/${id}`)
return res.json()
}
export function load(id: number) {
fetchTask(id) // await し忘れ
const data: any = { id }
return data.title as string
}
src/task.ts
5:3 error Unsafe return of a value of type `Promise<any>` @typescript-eslint/no-unsafe-return
9:3 error Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator @typescript-eslint/no-floating-promises
10:15 error Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
11:15 error Unsafe member access .title on an `any` value @typescript-eslint/no-unsafe-member-access
await の付け忘れ(no-floating-promises)や any の素通しは、型情報つきルールで検出できます。 tsc では通るコードでも見つけられるのが利点です。
React の完成形
eslint-plugin-react@7.37.5 は peerDependencies が eslint 9.7 までで、ESLint 10 と入れると ERESOLVE になりました。 ESLint 10 では flat config 前提の @eslint-react/eslint-plugin が入れやすいです。
npm i -D eslint @eslint/js globals typescript-eslint typescript@6 @eslint-react/eslint-plugin
// eslint.config.js
import { defineConfig, globalIgnores } from 'eslint/config'
import js from '@eslint/js'
import tseslint from 'typescript-eslint'
import eslintReact from '@eslint-react/eslint-plugin'
import globals from 'globals'
export default defineConfig([
globalIgnores(['dist/']),
{
files: ['**/*.{ts,tsx}'],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
eslintReact.configs['recommended-typescript'],
],
languageOptions: { globals: globals.browser },
},
])
実行ログ
// TaskList.tsx
import { useEffect, useState } from 'react'
type Task = { id: number; title: string }
export function TaskList({ tasks }: { tasks: Task[] }) {
const [count, setCount] = useState(0)
if (tasks.length === 0) {
const [msg] = useState('タスクなし') // 条件分岐の中でフック
return <p>{msg}</p>
}
useEffect(() => {
setCount(tasks.length)
}, [])
return (
<ul>
{tasks.map((t) => <li>{t.title}</li>)}
<li>{count}</li>
</ul>
)
}
8:19 error @eslint-react/rules-of-hooks - React Hook "useState" is called conditionally. …
11:3 error @eslint-react/rules-of-hooks - React Hook "useEffect" is called conditionally. …
12:5 warning @eslint-react/set-state-in-effect - Do not call the 'set' function 'setCount' of 'useState' synchronously in an effect. …
13:6 warning @eslint-react/exhaustive-deps - React Hook useEffect has a missing dependency: 'tasks.length'. …
16:25 error @eslint-react/no-missing-key - Missing 'key' for element when rendering list.
(読みやすいように JSON 出力から整形しています)
@eslint-react 5.x には rules-of-hooks と exhaustive-deps が含まれています。 eslint-plugin-react-hooks@7.1.1 の configs.flat.recommended も一緒に入れたところ、同じ指摘が react-hooks/... と @eslint-react/... で2回ずつ表示されました。どちらか一方にそろえると結果が見やすくなります。
Vue の完成形
npm i -D eslint @eslint/js globals typescript-eslint typescript@6 eslint-plugin-vue
// eslint.config.js
import { defineConfig, globalIgnores } from 'eslint/config'
import js from '@eslint/js'
import tseslint from 'typescript-eslint'
import pluginVue from 'eslint-plugin-vue'
import globals from 'globals'
export default defineConfig([
globalIgnores(['dist/']),
{
files: ['**/*.{js,ts,vue}'],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
pluginVue.configs['flat/recommended'],
],
languageOptions: {
globals: globals.browser,
parserOptions: { parser: tseslint.parser }, // <script lang="ts"> を読む
},
},
])
.vue 全体は vue-eslint-parser、<script lang="ts"> の中は parserOptions.parser に渡したパーサーが読みます。 flat config 用の設定名は flat/recommended のように flat/ 付きです。
実行ログと --fix の前後
<!-- ItemList.vue -->
<script setup lang="ts">
import { ref } from 'vue'
const props = defineProps<{ items: { id: number; name: string }[] }>()
const keyword = ref('')
const unusedVar: any = 1
</script>
<template>
<input v-model="keyword">
<ul>
<li v-for="item in props.items" v-if="item.name.includes(keyword)">{{ item.name }}</li>
</ul>
</template>
5:7 error @typescript-eslint/no-unused-vars - 'unusedVar' is assigned a value but never used.
5:18 error @typescript-eslint/no-explicit-any - Unexpected any. Specify a different type.
11:5 error vue/require-v-for-key - Elements in iteration expect to have 'v-bind:key' directives.
11:37 warning vue/max-attributes-per-line - 'v-if' should be on a new line.
11:37 error vue/no-use-v-if-with-v-for - The 'props.items' expression inside 'v-for' directive should be replaced with a …
11:72 warning vue/singleline-html-element-content-newline - Expected 1 line break after opening tag (`<li>`), but no line breaks found.
11:87 warning vue/singleline-html-element-content-newline - Expected 1 line break before closing tag (`</li>`), but no line breaks found.
--fix 後は7件が4件になり、テンプレートは次のように整形されました。
- <li v-for="item in props.items" v-if="item.name.includes(keyword)">{{ item.name }}</li>
+ <li
+ v-for="item in props.items"
+ v-if="item.name.includes(keyword)"
+ >
+ {{ item.name }}
+ </li>
自動で直るのは見た目(改行・属性の配置)の3件で、v-for と v-if の同時使用や key の付け忘れは、コードの意図に合わせて人が直します。
Prettier と併用する完成形
整形は Prettier、問題検出は ESLint と分けるのが一般的です。eslint-config-prettier はPrettierとぶつかるルールをオフにします。
npm i -D prettier eslint-config-prettier
// eslint.config.js(Vue の完成形に追加)
import eslintConfigPrettier from 'eslint-config-prettier/flat'
export default defineConfig([
// ...ここまでの設定...
eslintConfigPrettier, // 最後に置いて整形系ルールをオフ
])
同じ ItemList.vue(修正前)を再度リントすると、整形系の警告3件(vue/max-attributes-per-line など)が消え、コードの問題4件(error)だけが残りました。 整形は npx prettier --check .(確認)と --write(修正)で行います。eslintConfigPrettier を配列の途中に置くと、後ろの設定で整形系ルールが再び有効になるため、必ず最後に置きます。
npx eslint-config-prettier vuex/ItemList.vue を実行すると No rules that are unnecessary or conflict with Prettier were found. と表示され、ぶつかるルールが残っていないことを確認できます。
Node.js の完成形
npm i -D eslint @eslint/js globals eslint-plugin-n
// eslint.config.js
import { defineConfig, globalIgnores } from 'eslint/config'
import js from '@eslint/js'
import nodePlugin from 'eslint-plugin-n'
import globals from 'globals'
export default defineConfig([
globalIgnores(['dist/']),
{
files: ['**/*.{js,mjs}'],
extends: [js.configs.recommended, nodePlugin.configs['flat/recommended-module']],
languageOptions: { globals: globals.nodeBuiltin },
},
])
// server.js
import { readFile } from 'node:fs/promises'
import { parse } from 'some-missing-lib'
const data = await readFile(new URL('./stock.json', import.meta.url), 'utf8')
console.log(parse(data), process.env.PORT, __dirname)
2:23 error n/no-missing-import - Can't resolve 'some-missing-lib' in '…/node'
5:44 error no-undef - '__dirname' is not defined.
ESMのプロジェクトでは globals.node ではなく globals.nodeBuiltin を使うと、ESMでは使えない __dirname を検出できます。 globals.node にした場合、__dirname の指摘は出ませんでした(CommonJS用のグローバルも含むため)。
設定の中身を確認する(config inspector)
npx eslint --inspect-config # ESLint 本体から起動
npx @eslint/config-inspector --port 7316
ブラウザで設定の一覧が開き(v3.5.0で確認)、どの設定がどのファイルにどの順で効いているかを確認できます。JavaScript の完成形では、既定の **/node_modules/ 除外、globalIgnores の dist/、js/recommended などの7項目が並びました。コマンドだけなら npx eslint --print-config src/order.js で最終的なルールをJSONで出せます。
eslintrc から移行する(@eslint/migrate-config)
ESLint 10で .eslintrc.json だけのプロジェクトを実行すると、次のエラーになります。
ESLint couldn't find an eslint.config.* file.
From ESLint v9.0.0, the default configuration file is now eslint.config.*.
移行元の .eslintrc.json です。
{
"root": true,
"env": { "browser": true, "es2022": true },
"parserOptions": { "ecmaVersion": "latest", "sourceType": "module" },
"extends": ["eslint:recommended"],
"ignorePatterns": ["dist/"],
"rules": { "no-var": "error", "prefer-const": "error", "eqeqeq": ["error", "always"] }
}
$ npx @eslint/migrate-config .eslintrc.json
Wrote new config to ./eslint.config.mjs
You will need to install the following packages to use the new config:
- globals
- @eslint/js
- @eslint/eslintrc
生成された eslint.config.mjs です(空行のみ詰めています)。
import { defineConfig, globalIgnores } from "eslint/config";
import globals from "globals";
import path from "node:path";
import { fileURLToPath } from "node:url";
import js from "@eslint/js";
import { FlatCompat } from "@eslint/eslintrc";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all
});
export default defineConfig([globalIgnores(["**/dist/"]), {
extends: compat.extends("eslint:recommended"),
languageOptions: {
globals: {
...globals.browser,
},
ecmaVersion: "latest",
sourceType: "module",
},
rules: {
"no-var": "error",
"prefer-const": "error",
eqeqeq: ["error", "always"],
},
}]);
env は globals、ignorePatterns は globalIgnores に自動で置き換わりました。 "eslint:recommended" は互換レイヤー(FlatCompat)経由になっているので、js.configs.recommended に置き換えると @eslint/eslintrc が不要になります。
整理後は、FlatCompat 関連の import と compat を削除し、files: ['**/*.{js,mjs,cjs}'] と extends: [js.configs.recommended] を書いた形になります(上の「JavaScript の完成形」と同じ構成です)。
自動生成版と整理版のどちらでも、同じ src/order.js に対して6件の同じエラーが検出されることを確認しました。 ecmaVersion: 'latest' と sourceType: 'module' は flat config の既定値なので省略できます。
その他の対応は、plugins: ['react'](文字列)→ plugins: { react: reactPlugin }(importしたオブジェクト)、overrides → 配列に { files, rules } を追加、です。
よくあるエラーと対処
ignore が効かない
// dist/ が除外されない書き方
export default defineConfig([
js.configs.recommended,
{
ignores: ['dist/'], // ← 他のキーと同じオブジェクトに書いている
languageOptions: { globals: globals.browser },
rules: { 'no-var': 'error' },
},
])
dist/bundle.js
1:7 error 'x' is assigned a value but never used no-unused-vars
ignores は、他のキーと同じオブジェクトに書くと「そのオブジェクトの設定を適用しないファイル」という意味になり、全体の除外にはなりません。 globalIgnores(['dist/']) を使うと、明示的に指定しても次のように除外されます。
$ npx eslint dist/bundle.js
dist/bundle.js
0:0 warning File ignored because of a matching ignore pattern. Use "--no-ignore" to disable file ignore settings or use "--no-warn-ignored" to suppress this warning
型情報を使うルールで parserOptions がない
Error: Error while loading rule '@typescript-eslint/await-thenable': You have used a rule which requires type information, but don't have parserOptions set to generate type information for this file. See https://tseslint.com/typed-linting for enabling linting with type information.
recommendedTypeChecked を使うときは parserOptions.projectService: true と tsconfigRootDir を設定します。tsconfig の include に入っていないファイルでは、次のエラーになりました。
scripts/tool.ts
0:0 error Parsing error: scripts/tool.ts was not found by the project service. Consider either including it in the tsconfig.json or including it in allowDefaultProject
tsconfig の include に追加するか、設定ファイルなど少数のファイルなら projectService: { allowDefaultProject: ['*.js'] } で許可します。
その他のエラー早見表
| エラー文・症状 | 原因 | 対処 |
|---|---|---|
Cannot find package 'eslint-plugin-vue' imported from …/eslint.config.js |
プラグイン未インストール | npm i -D eslint-plugin-vue |
ESLint couldn't find an eslint.config.* file. |
eslintrc のみ | @eslint/migrate-config で移行 |
ERESOLVE … peer typescript@">=4.8.4 <6.1.0" |
TypeScript 7 と typescript-eslint 8 | typescript@6 を入れる |
| 同じ指摘が2回出る | 同じルールを持つプラグインを両方有効化 | どちらかに統一 |
| 下の階層だけ設定が変わる | v10 は最も近い eslint.config.* を使う |
設定ファイルを1つにまとめる |
最後の行は、node/ に no-console だけの eslint.config.js を置いて確認しました。ルート側の設定は使われず no-console のみが報告され、最も近い設定ファイルだけが使われる(上の階層と合成されない)ことがわかります。
よくある質問
Q. eslint.config.js と eslint.config.mjs のどちらにすればよいですか?
A. package.json に "type": "module" があれば .js で import 構文が使えます。ない場合は .mjs にします。TypeScriptで書く eslint.config.ts も使えます(jiti 2.2.0以上が必要)。
Q. tseslint.config() と defineConfig() はどちらを使えばよいですか?
A. ESLint 本体の defineConfig(eslint/config)で extends が書けるので、この記事のように defineConfig の中で typescript-eslint の設定を使えます。tseslint.config() も引き続き提供されています。
Q. ESLint 9 の flat config は、10 でも書き換えずに動きますか?
A. flat config の書き方は同じです。v10 で変わったのは、/* eslint-env */ コメントがエラーになる点、設定ファイルを対象ファイルの場所から探す点、eslint:recommended へのルール追加などです。上げたあとに npx eslint . で新しい指摘を確認します。
まとめ
- ESLint 10 では
eslint.config.*(flat config)が唯一の設定方式 defineConfig+extends+globalIgnoresの3点で、読みやすい設定が書ける- 型情報つきルールは
projectService: trueで有効化。await忘れなどを検出できた - ESLint 10 と組み合わせるなら React は @eslint-react、TypeScript は 6.0.x(2026年9月時点の peer 範囲)
- Prettier 併用は
eslint-config-prettier/flatを最後に置き、整形系の警告3件が消えることを確認 ignoresは単独オブジェクトかglobalIgnoresで書くと全体から除外される- 移行は
@eslint/migrate-config→FlatCompatを外して整理の2段階で進めると確実
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「ESLint flat config設定|v10対応の完成形コピペ集」
株式会社RJCでは、リントや開発環境の設定を実際に動かして確かめ、チームで使いやすい形をプロジェクトの中で仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。