lint-staged の使い方完全ガイド
一言でいうと
lint-staged は、Gitでステージング(git add)されたファイルだけを対象に、ESLintやPrettierなどのコード品質チェック・フォーマットタスクを実行するツールです。プロジェクト全体ではなく変更ファイルのみを処理するため、高速かつ的確にコード品質を担保できます。
どんな時に使う?
- コミット前にESLint/Prettierを自動実行したい — Huskyなどのgit hookと組み合わせ、フォーマット忘れやLintエラーのあるコードがリポジトリに入るのを防ぎたい場合
- 大規模プロジェクトでLint実行を高速化したい — プロジェクト全体のLintは時間がかかるため、変更されたファイルだけに絞って実行したい場合
- モノレポで各パッケージごとに異なるタスクを設定したい — パッケージごとに設定ファイルを配置し、フロントエンドとバックエンドで別々のLintルールを適用したい場合
インストール
# npm
npm install --save-dev lint-staged
# yarn
yarn add --dev lint-staged
# pnpm
pnpm add --save-dev lint-staged
lint-staged単体ではgit hookの設定は行いません。通常は Husky と組み合わせて使います。
# Huskyのセットアップ例
npm install --save-dev husky
npx husky init
echo "npx lint-staged" > .husky/pre-commit
基本的な使い方
最もシンプルな構成は、package.json に設定を記述するパターンです。
// package.json
{
"name": "my-project",
"devDependencies": {
"eslint": "^9.0.0",
"prettier": "^3.0.0",
"lint-staged": "^16.4.0",
"husky": "^9.0.0"
},
"lint-staged": {
"*.{js,ts,jsx,tsx}": "eslint --fix",
"*.{json,md,css,scss}": "prettier --write"
}
}
この設定により、git commit 実行時に以下が自動的に行われます:
- ステージングされたファイルのうち
.js,.ts,.jsx,.tsxに対してeslint --fixを実行 - ステージングされたファイルのうち
.json,.md,.css,.scssに対してprettier --writeを実行 - タスクによる修正があれば、自動的にステージングに追加してコミットに含める
- エラーがあればコミットを中断
# 実際の流れ
git add src/index.ts
git commit -m "feat: add new feature"
# → lint-stagedが自動実行 → ESLintとPrettierが走る → 問題なければコミット完了
よく使うAPI・設定パターン
1. 設定ファイルの形式
lint-stagedは複数の設定ファイル形式をサポートしています。
// .lintstagedrc.js(推奨:柔軟性が高い)
export default {
"*.{js,ts}": "eslint --fix",
"*.css": "stylelint --fix",
"*.{json,md}": "prettier --write",
};
// .lintstagedrc.json
{
"*.{js,ts}": "eslint --fix",
"*.{json,md}": "prettier --write"
}
# .lintstagedrc.yml
"*.{js,ts}":
- eslint --fix
"*.{json,md}":
- prettier --write
2. 複数コマンドの順次実行
1つのglobパターンに対して配列で複数コマンドを指定すると、順番に実行されます。
// package.json
{
"lint-staged": {
"*.ts": [
"eslint --fix",
"prettier --write"
]
}
}
この場合、まず eslint --fix が実行され、成功したら prettier --write が実行されます。
3. JS設定ファイルで動的にコマンドを生成
関数を使うことで、ファイルリストに基づいた動的なコマンド生成が可能です。
// lint-staged.config.js
export default {
"*.ts": (filenames) => {
// ファイル数が多い場合はチャンクに分割するなどの制御が可能
const files = filenames.join(" ");
return [
`eslint --fix ${files}`,
`prettier --write ${files}`,
];
},
// テストファイルだけ型チェックも実行
"*.spec.ts": () => "tsc --noEmit",
};
ポイント: 関数形式では引数にマッチしたファイルパスの配列が渡されます。
tscのようにファイル指定が不要なコマンドでは、引数を無視して文字列を返すだけでOKです。
4. コマンドラインフラグ
# デバッグ情報を出力(トラブルシューティング時に便利)
npx lint-staged --debug
# タスクを直列実行(並列実行で問題が出る場合)
npx lint-staged --concurrent false
# タスクがすべての変更を取り消した場合でも空コミットを許可
npx lint-staged --allow-empty
# 相対パスでファイルを渡す
npx lint-staged --relative
# 設定ファイルを明示的に指定
npx lint-staged --config path/to/.lintstagedrc.js
# タスクがファイルを変更した場合にエラーで終了(CIで便利)
npx lint-staged --fail-on-changes
# 成功時もタスクの出力を表示
npx lint-staged --verbose
5. モノレポでの設定
モノレポでは各パッケージディレクトリに個別の設定ファイルを配置できます。
my-monorepo/
├── .husky/
│ └── pre-commit # npx lint-staged
├── package.json
├── packages/
│ ├── frontend/
│ │ ├── .lintstagedrc.json # フロントエンド用設定
│ │ └── src/
│ └── backend/
│ ├── .lintstagedrc.json # バックエンド用設定
│ └── src/
// packages/frontend/.lintstagedrc.json
{
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
"*.css": "stylelint --fix"
}
// packages/backend/.lintstagedrc.json
{
"*.ts": "eslint --fix",
"*.prisma": "prisma format"
}
lint-stagedはステージングされたファイルの位置から最も近い設定ファイルを自動的に検出します。
類似パッケージとの比較
| 特徴 | lint-staged | nano-staged | pretty-quick |
|---|---|---|---|
| 対象 | ステージングされたファイル全般 | ステージングされたファイル全般 | Prettierのみ |
| 任意コマンド実行 | ✅ | ✅ | ❌(Prettier専用) |
| globパターン | ✅(micromatch) | ✅ | ❌ |
| JS設定ファイル(関数) | ✅ | ❌ | ❌ |
| モノレポ対応 | ✅(複数設定ファイル) | △ | △ |
| バンドルサイズ | やや大きい | 軽量 | 軽量 |
| コミュニティ・実績 | ◎(非常に大きい) | △ | ○ |
| 部分ステージング対応 | ✅(unstaged変更を隠す) | ✅ | ❌ |
選定の目安:
- 汎用的にLint/Format/テストを実行したい → lint-staged(デファクトスタンダード)
- とにかく軽量にしたい → nano-staged
- Prettierだけ走らせたい → pretty-quick
注意点・Tips
部分ステージング(partial staging)の挙動を理解する
lint-stagedはデフォルトで、部分的にステージングされたファイルのunstaged部分を一時的に隠します。これにより、タスクはステージングされた内容のみを対象に実行されます。
# ファイルの一部だけステージングした場合
git add --patch src/index.ts
git commit # lint-stagedはステージングされた部分だけを対象にする
--no-stash の使用は慎重に
lint-stagedはデフォルトでタスク実行前にgit stashでバックアップを作成します。--no-stash を指定するとこのバックアップが無効になり、タスク失敗時にデータが失われるリスクがあります。
# バックアップが失われた場合の復元方法
git stash list --format="%h %s"
# h0a0s0h0 On main: lint-staged automatic backup
git apply --index h0a0s0h0
eslint --fix と prettier --write の実行順序
両方を使う場合、ESLint → Prettier の順で実行するのが一般的です。ESLintの自動修正後にPrettierでフォーマットを整えることで、競合を避けられます。
{
"lint-staged": {
"*.{ts,tsx}": [
"eslint --fix",
"prettier --write"
]
}
}
ただし、eslint-config-prettier を導入してESLint側のフォーマットルールを無効化しておくと、より安定します。
CIでの活用
CIではコミットフックが動かないため、--fail-on-changes フラグを --diff と組み合わせて使うことで、フォーマット漏れを検出できます。
# CIでmainブランチとの差分ファイルをチェック
npx lint-staged --diff="origin/main...HEAD" --fail-on-changes
TypeScriptの型チェックを組み込む場合の注意
tsc はファイル単位の指定に対応していないため、関数形式で引数を無視する必要があります。
// lint-staged.config.js
export default {
"*.ts": () => "tsc --noEmit --pretty",
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
};
注意:
tsc --noEmitはプロジェクト全体を対象に実行されるため、ステージングされたファイルだけでなく全ファイルの型エラーが報告されます。これが意図した挙動かどうか確認してください。
まとめ
lint-stagedは、ステージングされたファイルだけを対象にLintやフォーマットを実行することで、コミット前のコード品質チェックを高速かつ確実に行えるツールです。Huskyと組み合わせるだけで、チーム全体のコード品質を自動的に底上げできます。設定もシンプルなglobパターンベースで直感的に書けるため、新規プロジェクトでも既存プロジェクトでも導入コストが低く、まさにデファクトスタンダードと言える存在です。