Last Updated: February 25, 2016
· amoniker

Never Refresh Again

How about an easy to way eliminate thousands of keystrokes? Grunt can do that.

Grunt is an excellent tool that can automate many of the things we do during web development. The result is that you get more time to focus on building while avoiding repetitive minutae.

In this protip, we'll focus on one aspect of Grunt - watching for changes to files and automatically refreshing the browser in response. There are a few steps to get set up, but the end result is worth it.

If you've never used Grunt, it's easy to get started. First, make sure you have node.js and npm installed. You won't have to write (much) node code, but Grunt needs it to run. There are a bunch of ways to install, so pick the one that's easiest for your platform.

Once that's settled, let's get the grunt command-line interface. Install it by running:

sudo npm install -g grunt-cli

This makes the grunt command available within a terminal.

Next, navigate to your web project's directory. We'll use npm to set up the package.json configuration file. Run the following command and it will guide you through a short initialization sequence.

npm init

Good. Now you've got a package.json file and are ready to install the two grunt dependencies we'll use. The first is the grunt module, and the second is the grunt-contrib-watch plugin. Install both like this:

npm install grunt --save-dev

npm install grunt-contrib-watch --save-dev

Notice that --save-dev flag. It will add entries to the devDependencies section of package.json. Look in that file and you'll see that it keeps a record of which npm packages are required for the project.

It's a good idea to commit package.json to source control so that new dev environments can be set up quickly. If you're working with a team, they'll only have to run npm install to get all the necessary dependencies automatically.

Alright. Next we'll set up a file named Gruntfile.js which will tell Grunt what to do. There are lots of excellent plugins which can do various things like sass compilation, javascript uglification, js linting, and more - but for the sake of this protip's scope we'll limit ourselves to the grunt-contrib-watch plugin.

Our basic Gruntfile.js will look something like this:

module.exports = function(grunt) {
    pkg: grunt.file.readJSON('package.json'),
    watch: {
      foobar: {
        files: ['**/*.js'],
        options: {
          livereload: true


  grunt.registerTask('default', ['watch']);

Let's break it down.

module.exports is the wrapper for node modules (like Grunt!)

grunt.initConfig() tells grunt which plugins and tasks we'd like to make available, and how each one should be configured. Other than feeding in the package.json file, our only task is watch.

The foobar key in the watch object can be named anything you like. You could call it scripts, files, css, etc. It tells the watch plugin that you'd like it to look for any changes to the files within. For this example, it will respond to any files matching **/*.js (which means any .js file in any subdirectory).

When a .js file is changed, Grunt will notice and run everything in the tasks array of the foobar object. But... wait. We didn't put any tasks in foobar. That's OK. In this example we're only going to refresh the browser, which is a feature built into grunt-contrib-watch and doesn't require additional tasks. However, if you want to add some tasks (like minification or sass compilation) then those would run before the browser refreshes. Pretty handy.

Now, the options object is what enables livereload which is where the magic happens. After all tasks have run (if there are any) the LiveReload server will be notified that it's time to refresh. Once our browser is set up to handle this, we won't have to press ⌘⇧R anymore!

Lastly, the default task is what grunt runs when it's invoked without any command-line arguments. Here we've made the default watch. So, on the command line, just run grunt in your project directory (where your Gruntfile is), and grunt will go into watch mode.

If you set it up like the example, run grunt and you should see:

Running "watch" task


We're so close!

The last step is to activate LiveReload in your browser. The simplest way is to use a browser extension. Once installed, enable it by clicking the icon in the upper right. Now it should refresh when changes are made to .js files within your project. When this happens you should also see some console messages in the terminal where grunt is running. Try it out!

Something that's even more fun is to enable LiveReload by adding a <script> tag to your web app's header. This is really useful if you have a bunch of devices (phone, tablet, etc.) that you'd like to keep nearby and automatically refresh along with your desktop browser. Of course, these devices must be able to connect to your dev site already, and they also need to be able to connect to your local machine's IP (or whichever machine grunt is running on).

If you want to do this, point the script tag at http://your.local.machine.ip:35279/livereload.js?snipver=1
(Mine looks like <script type="text/javascript" src=""></script>). Again, this IP should point to the machine grunt is running on. This way, you don't need a browser plugin and you can auto-reload in nearly any environment. (IE excluded, naturally)

One last note to make you giddy with delight. CSS changes are special when using LiveReload - they happen without a refresh. That is, they are applied instantly within your browser. This feels like magic, and it makes responsive development a breeze.

I hope you've found this guide useful. Thank you to everyone who helped build Node.js, npm, grunt, and LiveReload!

More documentation on grunt and grunt-contrib watch can be found at http://gruntjs.com/ and https://github.com/gruntjs/grunt-contrib-watch