eslint, semistandard, standard, and xo are all tools designed to enforce code quality and consistency in JavaScript projects by identifying problematic patterns, stylistic issues, and potential bugs. eslint is a highly configurable linter that serves as the foundation for many style guides. standard, semistandard, and xo are opinionated wrappers built on top of eslint that provide predefined rule sets with minimal or zero configuration required. While standard enforces a strict no-semicolons style, semistandard allows semicolons but otherwise follows standard's conventions. xo offers a modern, slightly more flexible alternative with sensible defaults focused on ES2020+ features and common best practices.
Choosing a JavaScript linter isn't just about catching bugs — it's about defining how your team writes code every day. The four tools here represent different philosophies: from total configurability (eslint) to rigid convention (standard), with pragmatic middle grounds in between. Let's break down how they actually work in practice.
eslint starts with no rules enabled by default. You must explicitly configure everything.
// .eslintrc.js
module.exports = {
env: { es2021: true, node: true },
extends: ['eslint:recommended'],
rules: {
'no-console': 'warn',
'indent': ['error', 2],
'quotes': ['error', 'single']
}
};
standard provides zero configuration. No config file needed — just install and run.
# No .eslintrc, no config
npx standard
semistandard also offers zero configuration, but differs from standard only in semicolon handling.
# Same zero-config approach
npx semistandard
xo uses sensible defaults with optional overrides. Most projects need no config, but you can customize via package.json.
// package.json
{
"xo": {
"semicolon": false,
"space": true
}
}
Here's how each tool handles basic formatting:
// Input code
function greet(name) {
return "Hello, " + name
}
const message = greet('World')
console.log(message)
eslint (with recommended config) won't flag any of this — you'd need to enable specific style rules.
standard will complain about missing semicolons and double quotes:
# standard output
2:30 error Strings must use single quotes
2:39 error Missing semicolon
5:30 error Missing semicolon
semistandard only complains about the quotes (allows semicolons):
# semistandard output
2:30 error Strings must use single quotes
xo by default requires semicolons and single quotes:
# xo output
2:30 error Strings must use single quotes
2:39 error Missing semicolon
5:30 error Missing semicolon
eslint has the richest ecosystem. You can extend configs, write custom rules, and integrate with frameworks:
// Using popular configs and plugins
module.exports = {
extends: [
'eslint:recommended',
'plugin:react/recommended',
'@typescript-eslint/recommended'
],
plugins: ['react', '@typescript-eslint']
};
standard, semistandard, and xo all build on eslint internally but limit customization:
standard/semistandard: Can add global variables only via CLI flags or comments
/* eslint-env browser */
/* global myGlobal */
xo: Supports some config overrides and ignores, plus limited plugin support:
{
"xo": {
"extends": ["plugin:react/recommended"],
"plugins": ["react"]
}
}
eslint supports everything through parsers and plugins:
// For TypeScript
module.exports = {
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint']
};
standard and semistandard only support JavaScript (ES2020+). No TypeScript support.
xo supports TypeScript with additional setup:
npm install --save-dev typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin
Then configure in package.json:
{
"xo": {
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"]
}
}
All four tools support automatic fixing, but with different workflows:
eslint:
npx eslint --fix src/
standard:
npx standard --fix
semistandard:
npx semistandard --fix
xo:
npx xo --fix
However, standard and semistandard have more limited auto-fix capabilities compared to eslint and xo, especially for complex stylistic issues.
You're building a large application with multiple teams, custom coding standards, and framework-specific rules.
eslintYou're publishing a small utility library and want contributors to follow consistent style without configuration debates.
standard or semistandardYou're building a new React application using TypeScript and hooks, wanting modern defaults with room for minor adjustments.
xoYou're gradually introducing linting to a large existing codebase with inconsistent style.
eslint| Feature | eslint | standard | semistandard | xo |
|---|---|---|---|---|
| Configuration | Full control | Zero config | Zero config | Minimal config |
| Semicolons | Configurable | Forbidden | Required | Required (configurable) |
| Extensibility | Unlimited | Very limited | Very limited | Moderate |
| TypeScript | Yes (with plugins) | No | No | Yes (with setup) |
| Auto-fix | Comprehensive | Basic | Basic | Good |
| Learning Curve | Steep | None | None | Low |
eslint — it's the industry standard for a reason.standard (no semicolons) or semistandard (with semicolons).xo gives you the best balance of opinionated defaults and escape hatches.Remember: the best linter is the one your team actually uses consistently. Don't let perfect be the enemy of good — even basic linting catches real bugs and prevents style arguments that waste valuable development time.
Choose semistandard if your team prefers using semicolons in JavaScript but still wants the simplicity and zero-configuration benefits of the standard style guide. It's a good middle ground for developers who find standard's no-semicolon rule too restrictive but appreciate its other conventions around spacing, naming, and code structure.
Choose eslint when you need full control over your linting rules, custom configurations, or integration with complex project requirements. It's ideal for large teams or organizations that require tailored coding standards, support for multiple environments (browser, Node.js, etc.), or gradual adoption of linting rules through overrides and plugins.
Choose standard when you want a completely zero-configuration linter that enforces a consistent style without any decision-making overhead. It's well-suited for small to medium projects where team members agree to adopt its opinionated rules, including no semicolons, 2-space indentation, and single quotes, allowing everyone to focus on logic rather than formatting debates.
Choose xo if you prefer a modern, slightly more flexible opinionated linter that supports the latest JavaScript features out of the box while still requiring minimal configuration. It's ideal for new projects using ES2020+ syntax, TypeScript (with additional setup), and developers who want sensible defaults with easy overrides for specific rules without abandoning the zero-config philosophy entirely.
All the goodness of standard/standard with semicolons sprinkled on top.
npm install semistandard
Importantly:
Use this in one of your projects? Include one of these badges in your readme to let people know that your code is using the standard style.
[](https://github.com/standard/semistandard)
[](https://github.com/standard/semistandard)
The easiest way to use JavaScript Semi-Standard Style to check your code is to install it
globally as a Node command line program. To do so, simply run the following command in
your terminal (flag -g installs semistandard globally on your system, omit it if you want
to install in the current working directory):
npm install semistandard -g
After you've done that you should be able to use the semistandard program. The simplest use
case would be checking the style of all JavaScript files in the current working directory:
$ semistandard
Error: Use JavaScript Semi-Standard Style
lib/torrent.js:950:11: Expected '===' and instead saw '=='.
package.json{
"name": "my-cool-package",
"devDependencies": {
"semistandard": "*"
},
"scripts": {
"test": "semistandard && node my-normal-tests-littered-with-semicolons.js"
}
}
npm test$ npm test
Error: Code style check failed:
lib/torrent.js:950:11: Expected '===' and instead saw '=='.
To use a custom parser, install it from npm (example: npm install babel-eslint) and add this to your package.json:
{
"semistandard": {
"parser": "babel-eslint"
}
}
Install Syntastic and add these lines to .vimrc:
let g:syntastic_javascript_checkers=['standard']
let g:syntastic_javascript_standard_exec = 'semistandard'
For automatic formatting on save, add these two lines to .vimrc:
autocmd bufwritepost *.js silent !semistandard % --fix
set autoread
Just like in standard, The paths node_modules/**, *.min.js, bundle.js, coverage/**, hidden files/folders
(beginning with .), and all patterns in a project's root .gitignore file are
automatically excluded when looking for .js files to check.
Sometimes you need to ignore additional folders or specific minfied files. To do that, add
a semistandard.ignore property to package.json:
"semistandard": {
"ignore": [
"**/out/",
"/lib/select2/",
"/lib/ckeditor/",
"tmp.js"
]
}
snazzyIf you want prettier output, just install the snazzy package and pipe semistandard to it:
$ semistandard --verbose | snazzy
See standard/standard for more information.