Grunt watch not triggering tasks on file save
Diagnose why Grunt watch skips lint, test, or build tasks after file saves, with checks for globs, process state, and Linux inotify limits.
08 Sept 2026, 11:14 UTC

Problem: saved files do not start Grunt tasks
You edit a source file and save it, but Grunt does not run the lint, test, or build task attached to grunt-contrib-watch. The watch terminal either stays silent or stops printing change events. This guide helps you isolate whether the cause is the watch process, the file glob patterns in your Gruntfile, or the operating system's file-watcher limit.
Useful takeaway: start with verbose output, confirm your globs match the actual edited file paths, then check inotify headroom if you are on Linux.
Recognizable condition
The symptom is specific: file changes are saved, but no registered task executes. The watch process may still be running, or it may have exited after a configuration error.
Cause and diagnostic table
| Symptom | Likely cause | First check |
|---|---|---|
| No terminal output after saving any watched file | Watch process is not running, or Gruntfile failed to load | Run grunt watch --verbose and look for "Waiting" |
| Tasks run for some files but not others | src glob or cwd does not match edited paths | Inspect initConfig watch target against actual file paths |
| Events stop after many saves, especially on Linux | OS inotify watcher limit exhausted | Read /proc/sys/fs/inotify/max_user_watches |
Ordered checks
Check 1: confirm the watch process is active
Run this in the project root, in the same terminal where you started watch:
grunt watch --verbose
Where: project root directory. Permissions: none; this is read-only diagnostics. Expected result: Grunt prints a line such as Waiting... and remains running. When you save a watched file, it should print a change event and the task name. Risk: none. If the command exits with a stack trace, fix the Gruntfile error before proceeding.
Check 2: verify glob patterns match edited files
Open Gruntfile.js in the project root and inspect the watch configuration. A minimal example looks like this:
module.exports = function(grunt) {
grunt.initConfig({
watch: {
scripts: {
files: ['src/**/*.js'],
tasks: ['jshint'],
options: { spawn: false }
}
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
};
Where: Gruntfile.js. Permissions: read to inspect; write only to fix, and test changes on a branch first. Expected result: the path of the file you edited matches the files glob. If your editor saves outside src/ or the glob uses a nonstandard cwd, the event never reaches the task. Risk: editing the production Gruntfile without version control can break the build for other developers.
Check 3: check Linux file-watcher limits
On Linux, Grunt's native file watching depends on inotify. Each watched file consumes a watcher slot. When the limit is reached, new changes are silently ignored.
cat /proc/sys/fs/inotify/max_user_watches
Where: Linux build or development machine. Permissions: read for this command. Expected result: a number with comfortable headroom above the number of watched files. If the value is low or close to your watch count, increase it:
sudo sysctl -w fs.inotify.max_user_watches=524288
Permissions: root or sudo; this changes kernel state. Risk: the change may reset after reboot unless persisted in /etc/sysctl.conf. Verify the new value with the cat command above.
Fixes tied to findings
- Watch not running: restart
grunt watch. grunt-contrib-watch reads the Gruntfile when it starts, so configuration changes do not apply to an already-running process. - Glob mismatch: correct the
filesarray orcwdso the edited file path is included. Prefer explicit patterns such assrc/**/*.jsover broad patterns that may miss new directories. - Inotify limit exhausted: raise
fs.inotify.max_user_watchesas shown above. If you cannot change kernel settings, enable polling-based watching if your installed version of grunt-contrib-watch supports it; consult the plugin documentation for your version, because option names and behavior differ across releases.
Escalation criteria
Escalate only after you have reproduced the issue with a minimal setup:
- Create a temporary Gruntfile with a single watch target and one task, such as
jshintor a custom task that logs a message. - Create a temporary file that matches the watch glob, save it, and confirm the task executes.
- Compare
node --versionandgrunt --versionagainst theenginesfield and plugin peer dependencies inpackage.json.
If the minimal reproduction still fails, include the verbose output, Gruntfile watch section, and OS version when seeking support.
Limitations and verification
Grunt is in maintenance mode; prefer modern task runners for new projects unless you are maintaining a legacy build. Polling fallback increases CPU usage and should be disabled in CI. Native file-watching behavior also varies across grunt-contrib-watch releases and Node.js versions.
Practical check: run grunt watch --verbose, save a watched file, and confirm the terminal prints the change event followed by the task output. Then create a temporary file matching the glob, save it, and confirm the associated task executes.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.