eslint、semistandard、standard、xo はすべて JavaScript プロジェクトにおけるコード品質の維持やコーディング規約の自動適用を目的としたツールです。これらは静的解析(リンティング)を行い、潜在的なバグやスタイル違反を検出します。eslint は高度にカスタマイズ可能なルールエンジンを提供し、他の3つは eslint をベースにした「プリセット」または「オピニオン型」の設定として機能します。standard はセミコロン不要・2スペースインデントなど独自のスタイルを採用し、semistandard はそれに対してセミコロンを許容する変種です。xo は現代的な JavaScript(ESNext、TypeScript 対応など)に特化し、より積極的なコード修正を推奨します。
フロントエンド開発において、コードの品質と一貫性を保つことは長期的な保守性に直結します。eslint、semistandard、standard、xo はいずれもこの課題に取り組むツールですが、アプローチと適用範囲が大きく異なります。現場の実情に即して、それぞれの特性を深掘りします。
eslint は「ルールエンジン」として設計されており、すべての設定を明示的に定義する必要があります。
.eslintrc.js や eslint.config.js(Flat Config)で詳細な設定が可能// eslint.config.js (Flat Config)
import js from '@eslint/js';
export default [
js.configs.recommended,
{
rules: {
'no-console': 'warn',
'indent': ['error', 2]
}
}
];
standard は「設定不要」をコンセプトに、あらかじめ決められたルールセットを提供します。
.standardrc での一部例外対応あり)// package.json
{
"scripts": {
"lint": "standard"
},
"devDependencies": {
"standard": "*"
}
}
semistandard は standard の派生版で、唯一の違いは「セミコロンを許容する」点です。
standard と同一// package.json
{
"scripts": {
"lint": "semistandard"
},
"devDependencies": {
"semistandard": "*"
}
}
xo は「モダン JavaScript 向けのオピニオン型リンター」として設計されています。
--fix)を積極的に推奨package.json の xo フィールドまたは xo.config.js で行う// package.json
{
"xo": {
"semicolon": false,
"space": true
}
}
eslint では任意のルールを自由に上書きできます。
// .eslintrc.js
module.exports = {
rules: {
'no-var': 'error',
'prefer-const': 'warn'
}
};
standard / semistandard では公式にカスタマイズが推奨されていませんが、.eslintrc を併用することで部分的に上書き可能です(非公式なワークアラウンド)。
// .eslintrc.json(standard と併用)
{
"extends": ["./node_modules/standard/eslintrc.json"],
"rules": {
"comma-dangle": "off"
}
}
xo では overrides や rules フィールドで公式にカスタマイズをサポートしています。
// xo.config.js
export default {
rules: {
'unicorn/filename-case': 'off'
}
};
eslint は公式プラグイン(@typescript-eslint、eslint-plugin-react など)との統合が標準的です。
// eslint.config.js
import reactPlugin from 'eslint-plugin-react';
export default [
{
plugins: { react: reactPlugin },
rules: { 'react/jsx-uses-react': 'error' }
}
];
xo は内部で eslint を使用しており、react、typescript、vue などのサポートがビルトインされています。
// xo は package.json に "type": "module" があれば自動で ESM 対応
// TypeScript ファイルがあれば自動で型チェックを有効化
一方、standard / semistandard はプラグイン対応が限定的で、主に JavaScript のみを対象とします。
すべてのツールが --fix オプションをサポートしていますが、その範囲に差があります。
eslint:
npx eslint --fix src/
standard:
npx standard --fix
semistandard:
npx semistandard --fix
xo:
npx xo --fix
ただし、xo はより積極的に修正を適用し、たとえば未使用の変数を自動削除するなど、eslint のデフォルトルールよりも踏み込んだ修正を行います。
eslint と xo は exit code を適切に返すため、CI での失敗検出が容易です。
# GitHub Actions
- run: npx eslint .
# エラーがあれば自動で job 失敗
standard / semistandard も同様ですが、出力形式が簡素なため、詳細なレポートが必要な場合は eslint + formatter の方が有利です。
以下のコードを各ツールでチェックした場合の挙動を比較します。
// sample.js
var foo = 'bar'
console.log(foo)
eslint(推奨ルールのみ): var の使用で警告、末尾セミコロンなしでエラー(ルール次第)standard: セミコロンなしでエラー、var 使用でエラー、2スペースでない場合もエラーsemistandard: var 使用でエラー(セミコロンは OK)xo: var 使用でエラー、末尾セミコロンなしでエラー(デフォルト設定)、さらに未使用変数なら警告standard または semistandard を選ぶと、設定不要で即座に一貫したスタイルが適用されます。xo が最もスムーズです。TypeScript や JSX のサポートが標準で含まれ、最新の構文にも追随しています。eslint が唯一の選択肢です。細かなルール調整、複数の技術スタックへの対応、カスタムルールの導入などが必須になるためです。eslint の --init 機能で既存コードに合わせたルールを生成し、徐々に厳格化するのが現実的です。standard 系は既存コードとの互換性が低く、一括修正が必要になることが多いです。eslintstandard(セミコロン不要)または semistandard(セミコロン可)xo重要なのは、一度選んだツールをチーム全体で徹底し、CI で強制することです。ツール自体よりも、一貫した運用の方が品質向上に大きく貢献します。
xo は最新の JavaScript 機能(ES2022+ や TypeScript)を積極的にサポートし、コードの現代化を促進したい場合に適しています。自動修正機能が充実しており、CI 統合もしやすい設計です。ただし、頻繁に更新されるため、安定性よりも先進性を重視するプロジェクト向きです。
semistandard は Standard スタイルをベースにしつつ、セミコロンの使用を許容したいチーム向けです。Standard の哲学(シンプルで設定不要)を尊重しつつ、セミコロン必須派の開発者にも配慮する妥協点として有効です。既存の Standard コードベースにセミコロンを段階的に導入したい場合にも適しています。
eslint はプロジェクトの要件に完全に合わせてルールを細かく調整したい場合に最適です。大規模チームや複数のサブプロジェクトを持つモノレポ環境では、共通のカスタム設定を共有することで一貫性を保ちつつ柔軟性も確保できます。ただし、初期設定とメンテナンスにはコストがかかります。
standard は「設定不要」を掲げ、最小限の構成で即座に一貫したコードスタイルを適用したい場合に選択します。新規プロジェクトで迅速に開発を始めたい、またはチーム内でスタイル議論を避けたい場合に特に有効です。ただし、ルールのカスタマイズがほぼ不可能なため、特定の規約に強く縛られることになります。
JavaScript/TypeScript linter (ESLint wrapper) with great defaults
Opinionated but configurable ESLint wrapper with lots of goodies included. Enforces strict and readable code. Never discuss code style on a pull request again! No decision-making. No eslint.config.js to manage. It just works!
It uses ESLint underneath, so issues regarding built-in rules should be opened over there.
XO requires your project to be ESM.

unicorn, import, ava, n and more.$ npm init xo.$ xo --fix.$ xo --open.compat option.eslint-config-xo-react for easy JSX and React linting with zero config.npm install xo --save-dev
You must install XO locally. You can run it directly with $ npx xo.
You'll need eslint-config-xo-vue for specific linting in a Vue app.
$ xo --help
Usage
$ xo [<file|glob> ...]
Options
--fix Automagically fix issues
--reporter Reporter to use
--space Use space indent instead of tabs [Default: 2]
--config Path to a XO configuration file
--semicolon Use semicolons [Default: true]
--react Include React specific parsing and xo-react linting rules [Default: false]
--prettier Format with prettier or turn off prettier-conflicted rules when set to 'compat' [Default: false]
--print-config Print the effective ESLint config for the given file
--version Print XO version
--open Open files with issues in your editor
--quiet Show only errors and no warnings
--stdin Validate/fix code from stdin
--stdin-filename Specify a filename for the --stdin option
--ignore Ignore pattern globs, can be set multiple times
--cwd=<dir> Working directory for files [Default: process.cwd()]
Examples
$ xo
$ xo index.js
$ xo *.js !foo.js
$ xo --space
$ xo --print-config=index.js
$ echo 'const x=true' | xo --stdin --fix
Tips
- Add XO to your project with `npm init xo`.
- Put options in xo.config.js instead of using flags so other tools can read it.
Any of these can be overridden if necessary.
if (condition) {}=== instead of ==Check out an example and the ESLint rules.
The recommended workflow is to add XO locally to your project and run it with the tests.
Simply run $ npm init xo (with any options) to add XO to create an xo.config.js.
You can configure XO options by creating an xo.config.js or an xo.config.ts file in the root directory of your project, or you can add an xo field to your package.json. XO supports all js/ts file extensions (js,cjs,mjs,ts,cts,mts) and popular framework extensions (vue,svelte,astro) automatically. A XO config is an extension of ESLint's Flat Config. Like ESLint, an XO config exports an array of XO config objects. XO config objects extend ESLint Configuration Objects. This means all the available configuration params for ESLint also work for XO. However, XO enhances and adds extra params to the configuration objects to make them easier to work with.
XO exports the types FlatXoConfig, XoConfigItem, and other types for you to get TypeScript validation on your config files.
examples:
xo.config.js
/** @type {import('xo').FlatXoConfig} */
const xoConfig = [...]
xo.config.ts
import {type FlatXoConfig} from 'xo';
const xoConfig: FlatXoConfig = [...]
export default [...] satisfies import('xo').FlatXoConfig
Type: string | string[] | undefined
Default: **/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx,vue,svelte,astro}
A glob or array of glob strings which the config object will apply. By default XO will apply the configuration to all files.
Tip: If you are adding additional
@typescript-eslintrules to your config, these rules will apply to JS files as well unless you separate them appropriately with thefilesoption.@typescript-eslintrules set to'off'or0, however, will have no effect on JS linting.
Type: string[]
Some paths are ignored by default, including paths in .gitignore. Additional ignores can be added here.
Tip: For global ignores, keep
ignoresas the only key in the config item. You can optionally set anameproperty. Adding more properties will cause ignores to be scoped down to your files selection, which may have unexpected effects.
Type: boolean | number
Default: false (tab indentation)
Set it to true to get 2-space indentation or specify the number of spaces.
This option exists for pragmatic reasons, but I would strongly recommend you read “Why tabs are superior”.
Type: boolean
Default: true (Semicolons required)
Set it to false to enforce no-semicolon style.
Type: boolean | 'compat'
Default: false
Format code with Prettier.
Prettier options will be based on your Prettier config. XO will then merge your options with its own defaults:
truefalseTo stick with Prettier's defaults, add this to your Prettier config:
export default {
singleQuote: false,
bracketSpacing: true,
};
If contradicting options are set for both Prettier and XO, an error will be thrown.
If the Prettier option is set to compat, instead of formatting your code automatically, XO will turn off all rules that conflict with Prettier code style and allow you to pass your formatting to the Prettier tool directly.
Type: boolean
Default: false
Adds eslint-plugin-react, eslint-plugin-react-hooks, and eslint-config-xo-react to get all the React best practices applied automatically.
XO will automatically lint TypeScript files (.ts, .mts, .cts, and .tsx) with the rules defined in eslint-config-xo-typescript#use-with-xo.
XO will handle the @typescript-eslint/parser project option automatically even if you don't have a tsconfig.json in your project.
You can opt out of XO's automatic tsconfig handling by specifying your own languageOptions.parserOptions.project, languageOptions.parserOptions.projectService, or languageOptions.parserOptions.tsconfigRootDir. Files in a config with these properties will be excluded from automatic tsconfig handling.
With the introduction of the ESLint flat config, many of the original goals of xo were brought into the ESLint core, and shareable configs with plugins became possible. Although we highly recommend the use of the xo cli, we understand that some teams need to rely on ESLint directly.
For these purposes, you can still get most of the features of xo by using our ESLint configuration helpers.
The xoToEslintConfig function is designed for use in an eslint.config.js file. It is NOT for use in an xo.config.js file. This function takes a FlatXoConfig and outputs an ESLint config object. This function will neither be able to automatically handle TS integration for you nor automatic Prettier integration. You are responsible for configuring your other tools appropriately. The xo cli, will, however, handle all of these details for you.
eslint.config.js
import xo from 'xo';
export default xo.xoToEslintConfig([{space: true, prettier: 'compat'}]);
Put a xo.config.js with your config at the root and do not add a config to any of your bundled packages.
To include files that XO ignores by default, add them as negative globs in the ignores option:
const xoConfig = [{ignores: ['!vendor/**']}];
export default xoConfig;
It means hugs and kisses.
The Standard style is a really cool idea. I too wish we could have one style to rule them all! But the reality is that the JS community is just too diverse and opinionated to create one code style. They also made the mistake of pushing their own style instead of the most popular one. In contrast, XO is more pragmatic and has no aspiration of being the style. My goal with XO is to make it simple to enforce consistent code style with close to no config. XO comes with my code style preference by default, as I mainly made it for myself, but everything is configurable.
XO is based on ESLint. This project started out as just a shareable ESLint config, but it quickly grew out of that. I wanted something even simpler. Just typing xo and be done. No decision-making. No config. I also have some exciting future plans for it. However, you can still get most of the XO benefits while using ESLint directly with the ESLint shareable config.
xo as a list of style errors, ordered by countShow the world you're using XO →
[](https://github.com/xojs/xo)
You can also find some nice dynamic XO badges on badgen.net.