# grunt-contrib-jshint is a small Grunt plugin with a long release history

> The plugin does one thing, which is run JSHint over a set of files inside a Grunt build, and the interesting part is the set of extra options it layers on top of JSHint, from a jshintrc pointer to warning suppression by code.

**gruntjs/grunt-contrib-jshint** — Validate files with JSHint.

- Repository: https://github.com/gruntjs/grunt-contrib-jshint
- Website: http://gruntjs.com/
- Stars: 702 · Forks: 187
- Language: JavaScript
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/gruntjs-grunt-contrib-jshint

## What the plugin actually is

grunt-contrib-jshint is described in one line as validating files with JSHint, and it is part of the Grunt plugin family whose entry point is tasks/jshint.js. The package metadata is small and tells you the shape of the thing: three runtime dependencies, chalk at about 4.1, hooker at 0.2.3 and jshint at about 2.13.6, plus a peer requirement of Node 10 or newer. The task itself is run with the grunt jshint command, and task targets, files and options may be specified according to the Grunt guide to configuring tasks. The readme is careful about the order of operations for a newcomer, because it points you at the Grunt getting started guide first, since that guide explains how to create a Gruntfile as well as how to install and use plugins, and only then gives the install command for this one.

```shell
npm install grunt-contrib-jshint --save-dev
```

And the one line that enables it inside a Gruntfile.

```js
grunt.loadNpmTasks('grunt-contrib-jshint');
```

The important detail is that any option you specify is passed through directly to JSHint, so the plugin is a thin configuration and reporting layer rather than a separate implementation of the linter.

## The extra options are where the plugin earns its place

Beyond the JSHint options there are a handful of plugin-specific ones, and each solves a specific problem. The globals option takes a map of global variable names to a boolean saying whether they are assignable, and the readme is precise that this is not a standard JSHint option but is passed into the JSHINT function as its third argument. The jshintrc option is either a string or true, and if it is true no config is sent to JSHint and JSHint searches for .jshintrc files relative to the files being linted, while a filename means the options and globals defined in that file are used instead. The file has to be valid JSON.

```json
{
  "curly": true,
  "eqnull": true,
  "eqeqeq": true,
  "undef": true,
  "globals": {
    "jQuery": true
  }
}
```

The warning is the one to internalise, because jshintrc settings are not merged with your Grunt options. The extensions option is a list of non-dot-js extensions to check, which is how you lint templates or configuration files. The ignores option is a list of files and directories to ignore, and it overrides your .jshintignore file if one is set and does not merge with it. And the force option, false by default, reports JSHint errors but does not fail the task, which is the switch you reach for when you are introducing the linter into an existing codebase.

## Reporting to a file instead of the console

The reporter and reporterOutput options are the pair that makes the plugin usable in a pipeline. The reporter option lets you modify the plugin's output, and by default it uses a built-in Grunt reporter. Setting the path to your own custom reporter, or to one of the built-in JSHint reporters, jslint or checkstyle, is how you get output in a format another tool can read. An external reporter works too, and the readme gives the example of jshint-stylish, installed as a dev dependency.

```shell
$ npm install --save-dev jshint-stylish
```

```js
options: {
    reporter: require('jshint-stylish')
}
```

The reporterOutput option names a filepath, and when it is set all the output is written to that filepath instead of printed to stdout. The reporterOutputRelative option, true by default, means the results use a relative filepath to reporterOutput, and if it is set to false the filepaths appear relative to the current folder instead. The option has no effect unless reporterOutput is set, which is the kind of detail that only matters when you are reading a report produced on a build agent.

## Three configuration patterns, and the one that catches people out

The usage examples show three shapes of configuration. The first is a wildcard target, where the all target lints the project's Gruntfile as well as all JavaScript files in the lib and test directories and their subdirectories, using the default JSHint options.

```js
// Project configuration.
grunt.initConfig({
  jshint: {
    all: ['Gruntfile.js', 'lib/**/*.js', 'test/**/*.js']
  }
});
```

The second is linting before and after concatenating, which exists because of an ordering problem. If the same target covers both the sources and the generated output, the generated file may be linted before it has been created by the concat task, and the readme says the answer is to lint the beforeconcat files first, then concat, then lint the afterconcat files, by running grunt jshint:beforeconcat concat jshint:afterconcat.

```js
// Project configuration.
grunt.initConfig({
  concat: {
    dist: {
      src: ['src/foo.js', 'src/bar.js'],
      dest: 'dist/output.js'
    }
  },
  jshint: {
    beforeconcat: ['src/foo.js', 'src/bar.js'],
    afterconcat: ['dist/output.js']
  },
});
```

The third is per-target option overrides, where a target without options uses the defaults and a target with options uses the merged task and target options, which is how you lint most of a project strictly and one directory loosely.

## Suppressing a single warning by code

One feature is unusual enough to deserve its own mention, because it is the kind of thing you cannot get from JSHint on its own. The readme shows a sample warning with its location, its code and its text, and then explains that you can toggle it by prepending a minus sign to the warning id as an option.

```shell
[L24:C9] W015: Expected '}' to have an indentation at 11 instead at 9.
```

```js
grunt.initConfig({
  jshint: {
    ignore_warning: {
      options: {
        '-W015': true,
      },
      src: ['**/*.js'],
    },
  },
});
```

The value of this is that the suppression is scoped to a target rather than to the whole project, so a style rule you do not want for one directory can be switched off there and left on everywhere else. It is also much easier to review than editing a shared .jshintrc, because the exemption is visible in the Gruntfile next to the files it applies to.

## The repository and the release history

The repository is small and conventional for a Grunt plugin, with a Gruntfile.js at the root, a tasks/ directory holding the task implementation, a test/ directory, a docs/ directory, a .jshintrc and a .jshintignore for the project to lint itself, an AUTHORS file, a CHANGELOG, a CONTRIBUTING.md, a LICENSE-MIT and a package-lock.json. The test script is grunt test, and the dev dependencies are the internal task set and grunt-contrib-nodeunit, which is the unit test runner Grunt plugins conventionally use. The release history in the readme is a good record of how a plugin like this ages. v3.2.0 in February 2022 bumped dependencies including JSHint itself. v3.0.0 in October 2020 bumped dependencies, switched to GitHub actions, ensured errors in the stdoutEqual callback are logged, and required Node 10 or newer. v2.1.0 updated to the latest JSHint, v2.0.0 dropped Node.js below 6 support, v1.0.0 replaced string prototype colours with chalk and updated the Grunt peer dependency to at least 0.4.0, and v0.11.1 fixed io.js compatibility issues along with other pathing fixes.

## Where this is the wrong choice

Three limits are worth naming. The first is that JSHint itself is the older of the two JavaScript linters, and the ecosystem has largely moved to ESLint, which handles modern syntax, plugins and configuration formats that JSHint does not. A new project starting from scratch will find more support and more tooling on the other side. The second is that the plugin is a Grunt plugin, and Grunt itself has been largely displaced by Gulp, npm scripts and the bundler-integrated tooling that arrived afterwards, so this is a plugin for a build system that a new project is unlikely to choose. The third is that the configuration model has sharp edges, particularly the non-merging of jshintrc with the Grunt options and the overriding of .jshintignore by the ignores option, both of which behave in ways that surprise people and that the readme states plainly but that a newcomer will hit anyway. What the plugin still offers is a well-trodden path for the projects still on Grunt, and the release history shows a project that has been maintained through several toolchain shifts without breaking.

## Conclusion

grunt-contrib-jshint suits a project that already runs Grunt and wants JSHint in the same build, and it suits anyone who needs the reporter to write to a file rather than the console, which is the feature that makes it usable in a continuous integration log. It is the wrong tool for a new project, because ESLint has largely taken over that role and a Grunt task is a way of running something you could run directly. It is also the wrong choice if you need type checking, since JSHint is a linter and not a type checker. Before adding it, read the option list, particularly the note that jshintrc settings are not merged with your Grunt options, because that single rule explains most of the confusion people have with the plugin. The last push was on 2026-06-21 and the newest tag is v3.2.0 from 2022-02-18.

## FAQ

### How do I add JSHint to a Grunt build?

Install the plugin with npm install grunt-contrib-jshint --save-dev, enable it in your Gruntfile with grunt.loadNpmTasks('grunt-contrib-jshint'), and configure a target. Running grunt jshint then lints the files in that target, and any option you set is passed straight through to JSHint.

### Can I use a .jshintrc file with grunt-contrib-jshint?

Yes, through the jshintrc option, which is either a string or true. With a filename, the options and globals in that file are used and the file must be valid JSON, and with true no config is sent to JSHint so it searches for .jshintrc files relative to the files being linted. Be aware that jshintrc settings are not merged with your Grunt options.

### How do I stop grunt-contrib-jshint from failing the build on errors?

Set the force option to true, which reports JSHint errors but does not fail the task. The plugin also lets you suppress a single warning by prepending a minus sign to its code as an option, for example '-W015': true, which is useful for silencing a style rule in one target only.

## Sources

- [gruntjs/grunt-contrib-jshint on GitHub](https://github.com/gruntjs/grunt-contrib-jshint)
- [License: MIT](https://github.com/gruntjs/grunt-contrib-jshint/blob/main/LICENSE)
- [Project website](http://gruntjs.com/)
- [README](https://github.com/gruntjs/grunt-contrib-jshint/blob/main/README.md)
- [Releases](https://github.com/gruntjs/grunt-contrib-jshint/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/gruntjs-grunt-contrib-jshint
