JavaScript happiness style linter

Build Status: Linux Build status: Windows Coverage Status XO code style Gitter

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 .eslintrc or .jshintrc to manage. It just works!

Uses ESLint underneath, so issues regarding rules should be opened over there.

JSX is supported by default, but you’ll need eslint-config-xo-react for React specific linting.


  • Beautiful output.
  • Zero-config, but configurable when needed.
  • Enforces readable code, because you read more code than you write.
  • No need to specify file paths to lint as it lints all JS files except for commonly ignored paths.
  • Config overrides per files/globs. (ESLint doesn’t support this)
  • Includes many useful ESLint plugins, like unicorn, import, ava, and more.
  • Caches results between runs for much better performance.
  • Super simple to add XO to a project with $ xo --init.
  • Fix many issues automagically with $ xo --fix.
  • Open all files with errors at the correct line in your editor with $ xo --open.
  • Specify indent and semicolon preferences easily without messing with the rule config.
  • Great editor plugins.


$ npm install --global xo


$ xo --help

    $ xo [<file|glob> ...]

    --init            Add XO to your project
    --fix             Automagically fix issues
    --reporter        Reporter to use
    --env             Environment preset  [Can be set multiple times]
    --global          Global variable  [Can be set multiple times]
    --ignore          Additional paths to ignore  [Can be set multiple times]
    --space           Use space indent instead of tabs  [Default: 2]
    --no-semicolon    Prevent use of semicolons
    --plugin          Include third-party plugins  [Can be set multiple times]
    --extend          Extend defaults with a custom config  [Can be set multiple times]
    --open            Open files with issues in your editor
    --quiet           Show only errors and no warnings
    --extension       Additional extension to lint [Can be set multiple times]
    --no-esnext       Don't enforce ES2015+ rules
    --cwd=<dir>       Working directory for files
    --stdin           Validate/fix code from stdin
    --stdin-filename  Specify a filename for the --stdin option

    $ xo
    $ xo index.js
    $ xo *.js !foo.js
    $ xo --space
    $ xo --env=node --env=mocha
    $ xo --init --space
    $ xo --plugin=react
    $ xo --plugin=html --extension=html
    $ echo 'const x=true' | xo --stdin --fix

    Put options in package.json instead of using flags so other tools can read it.

Note that the CLI will use your local install of XO when available, even when run globally.

Default code style

Any of these can be overridden if necessary.

  • Tab indentation (or space)
  • Semicolons (or not)
  • Single-quotes
  • No unused variables
  • Space after keyword if (condition) {}
  • Always === 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 $ xo --init (with any options) to add XO to your package.json or create one.


  "name": "awesome-package",
  "scripts": {
    "test": "ava"
  "devDependencies": {
    "ava": "^0.19.0"


  "name": "awesome-package",
  "scripts": {
    "test": "xo && ava"
  "devDependencies": {
    "ava": "^0.19.0",
    "xo": "^0.18.0"

Then just run $ npm test and XO will be run before your tests.


You can configure some options in XO by putting it in package.json:

  "name": "awesome-package",
  "xo": {
    "space": true

Globals and rules can be configured inline in files.


Type: Array
Default: ['node']

Which environments your code is designed to run in. Each environment brings with it a certain set of predefined global variables.


Type: Array

Additional global variables your code accesses during execution.


Type: Array

Some paths are ignored by default, including paths in .gitignore. Additional ignores can be added here.


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: Object

Override any of the default rules. See the ESLint docs for more info on each rule.

Please take a moment to consider if you really need to use this option.


Type: boolean
Default: true (semicolons required)

Set it to false to enforce no-semicolon style.


Type: Array

Include third-party plugins.


Type: Array, string

Use one or more shareable configs or plugin configs to override any of the default rules (like rules above).


Type: Array

Allow more extensions to be linted besides .js and .jsx. Make sure they’re supported by ESLint or an ESLint plugin.


Type: Object

Shared ESLint settings exposed to rules. For example, to configure the import plugin to use your webpack configuration for determining search paths, you can put {"import/resolver": "webpack"} here.


Type: string

ESLint parser. For example, babel-eslint if you’re using language features that ESLint doesn’t yet support.


Type: boolean
Default: true

Enforce ES2015+ rules. Disabling this will make it not enforce ES2015+ syntax and conventions.

*ES2015+ is parsed even without this option. You can already use ES2017 features like async/await.

Config Overrides

XO makes it easy to override configs for specific files. The overrides property must be an array of override objects. Each override object must contain a files property which is a glob string, or an array of glob strings. The remaining properties are identical to those described above, and will override the settings of the base config. If multiple override configs match the same file, each matching override is applied in the order it appears in the array. This means the last override in the array takes precedence over earlier ones. Consider the following example:

  "xo": {
    "semicolon": false,
    "space": 2,
    "overrides": [
        "files": "test/*.js",
        "esnext": false,
        "space": 3
         "files": "test/foo.js",
         "esnext": true
  • The base configuration is simply space: 2, semicolon: false. These settings are used for every file unless otherwise noted below.

  • For every file in test/*.js, the base config is used, but space is overridden with 3, and the esnext option is set to false. The resulting config is:

  "esnext": false,
  "semicolon": false,
  "space": 3
  • For test/foo.js, the base config is first applied, followed the first overrides config (its glob pattern also matches test/foo.js), finally the second override config is applied. The resulting config is:
  "esnext": true,
  "semicolon": false,
  "space": 3


Using a parent’s config

If you have a directory structure with nested package.json files and you want one of the child manifests to be skipped, you can do so by setting "xo": false. For example, when you have separate app and dev package.json files with electron-builder.


Put a package.json with your config at the root and add "xo": false to the package.json in your bundled packages.


What does XO mean?

It means hugs and kisses.

Why not Standard?

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.

Why not ESLint?

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.

Editor plugins

Build-system plugins





Show the world you’re using XO → XO code style

[![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo)


Sindre Sorhus James Talmage Mario Nebl Michael Mayer
Sindre Sorhus James Talmage Mario Nebl Michael Mayer



Related Repositories



xo, a command line utility that composes regular expression matches. ...



ESLint shareable config for XO ...



Linter for XO ...



ESLint shareable config for React to be used with eslint-config-xo ...



ESLint shareable config for XO ...

Top Contributors

sindresorhus jamestalmage kevva vdemedes joakimbeng claylo antleblanc arthurvr blainsmith brandon93s beatfreaker abhisekp dustinspecker jfmengels forivall lukeed rosszurowski SamVerschueren ntwb sterpe tcoenraad floatdrop j-em


package version
arrify ^1.0.0
debug ^2.2.0
deep-assign ^1.0.0
eslint ^3.18.0
eslint-config-xo ^0.18.0
eslint-formatter-pretty ^1.0.0
eslint-plugin-ava ^4.2.0
eslint-plugin-import ^2.0.0
eslint-plugin-no-use-extend-native ^0.3.2
eslint-plugin-promise ^3.4.0
eslint-plugin-unicorn ^2.1.0
get-stdin ^5.0.0
globby ^6.0.0
has-flag ^2.0.0
ignore ^3.2.6
lodash.isequal ^4.4.0
meow ^3.4.2
multimatch ^2.1.0
open-editor ^1.0.1
path-exists ^3.0.0
pkg-conf ^2.0.0
resolve-cwd ^2.0.0
resolve-from ^3.0.0
slash ^1.0.0
update-notifier ^2.1.0
xo-init ^0.5.0
dev ava *
coveralls ^2.11.9
eslint-config-xo-react ^0.12.0
eslint-plugin-react ^7.1.0
execa ^0.7.0
nyc ^11.0.3
pify ^3.0.0
proxyquire ^1.7.3
temp-write ^3.1.0
xo sindresorhus/xo#v0.18.2


-   v0.16.0 zip tar
-   v0.15.1 zip tar
-   v0.15.0 zip tar
-   v0.14.0 zip tar
-   v0.13.0 zip tar
-   v0.12.1 zip tar
-   v0.12.0 zip tar
-   v0.11.2 zip tar
-   v0.11.1 zip tar
-   v0.11.0 zip tar
-   v0.10.1 zip tar
-   v0.10.0 zip tar
-   v0.9.0 zip tar
-   v0.8.0 zip tar
-   v0.7.1 zip tar
-   v0.6.1 zip tar
-   v0.6.0 zip tar
-   v0.5.2 zip tar
-   v0.5.1 zip tar
-   v0.5.0 zip tar