How To Use Grunt To Automate Your Workflow [Tutorials]

I’m a huge advocate of automation because it makes life that much simpler. Why spend time on menial, monotonous tasks that suck your life-force right out when you have a computer to do things for you? This is especially true for web development.

automate workflow with grunt

Many development tasks can be a chore. While developing you may want to compile code, when pushing a development version you might concatenate and minify files, remove development only resources, and so on. Even relatively uncomplicated ones like deleting a bunch of files, or renaming folders can take up a large chunk of our time.

In this article I’ll show you how you can make your life easier by leveraging the excellent functionality offered by Grunt, a Javascript task runner. I’ll guide you through the whole process so no worries even if you’re not a Javascript wizard!

More on

Installing Grunt

Installing Grunt is pretty easy because it uses the node package manager. This means that you may also have to install Node itself. Open a terminal or a command prompt (I’ll be calling this terminal from now on) and enter nmp -v.

If you see a version number you have npm installed, if you see a "command not found" error, you’ll have to install it by going to the node downloads page and selecting the version you need.

Once Node is installed, getting Grunt is a matter of a single command issued in the terminal:

npm install -g grunt-cli

Basic Usage

You will be using Grunt on a project-to-project basis since each project will have different requirements. Let’s start a project now by creating a folder and navigating to it via our terminal as well.

Two files make up the heart of Grunt: package.json and Gruntfile.js. The package file defines all the third-party dependencies your automation will use, the Gruntfile lets you control how exactly these are used. Let’s create a bare-bones package file now with the following content:

{ "name": "test-project", "version": "1.0", "devDependencies": { "grunt": "~0.4.5", } }

The name and version is up to you, the dependencies must contain all packages you are using. We’re not doing anything at the moment so we’ll just make sure Grunt itself is added as a dependency.

You may be asking yourself what that squiggly line (~) called a tilde is doing there.

Versions can be required using the rules from the semantic versioner for npm. In a nutshell:

  • You specify an exact version like 4.5.2
  • You can use greater than/less than to indicate minimum or maximum version such as >4.0.3
  • Using the tilde specifies a version block. Using ~1.2 is considered to be 1.2.x, any version above 1.2.0 but below 1.3

A lot more ways of specifying versions is available but this is enough for most needs. The next step is to create a Gruntfile which will perform our automations.

 module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json') }); grunt.registerTask('default', [] ); }; 

This is basically the skeleton for a Gruntfile; there are two places of interest. One location is inside the initConfig() function. This is where all your project configuration goes. This will include things like handling LESS/SASS compiling, minifying scripts and so on.

The second location is below that function where you specify tasks. You can see one task specified named “default”. It is empty at the moment so it does nothing, but we’ll expand on that later. Tasks essentially queue up bits and pieces from our project configuration and execute them.

For example, a task named “scripts” may concatenate all our scripts, then minify the resulting file and then move it to its final location. These three actions are all defined in the project configuration but are “pulled together” by the task. If this isn’t clear just yet don’t worry, I’ll be showing you how this is done.

Our First Task

Let’s create a task which minifies a single javascript file for us.

There are four things we need to do any time we want to add a new task:

  • Install a plugin if necessary
  • Require it in the Gruntfile
  • Write a task
  • Add it to a task group if needed

(1) Find And Install Plugin

The easiest way to find the plugin you need is to type something like this into Google: “minify javascript grunt plugin”. The first result should lead you to the grunt-contrib-uglify plugin which is just what we need.

The Github page tells you all you need to know. Installation is a single line in the terminal, here’s what you need to use:

 npm install grunt-contrib-uglify --save-dev 

You may need to run this with admin priviledges. If you get something like npm ERR! Please try running this command again as root/Administrator. along the way just type sudo before the command and enter your password when prompted:

 sudo npm install grunt-contrib-uglify --save-dev 

This command actually parses your package.json file and adds it as a dependancy there, you will not need to do that manually.

(2) Require In Gruntfile

The next step is to add in your Gruntfile as a requirement. I like to add plugins at the top of the file, here’s my complete Gruntfile after adding grunt.loadNpmTasks('grunt-contrib-uglify');.

 module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.initConfig({ pkg: grunt.file.readJSON('package.json') }); grunt.registerTask('default', [] ); }; 

(3) Create a task for minifying scripts

As we discussed, this should be done within the initConfig() function. The Github page for the plugin (and most other plugins) gives you plenty of information and examples. Here’s what I used in my test project.

 uglify: { build: { src: 'js/scripts.js', dest: 'js/scripts.min.js' } } 

This is pretty straightforward, I specified the scripts.js file in my project’s js directory and the destination for the minified file. There are many ways to specify source files, we’ll take a look at that later.

For now, let’s take a look at the complete Gruntfile after this has been added, to make sure you know how things fit together.

 module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), uglify: { build: { src: 'scripts.js', dest: 'scripts.min.js' } } }); grunt.registerTask('default', [] ); }; 

(4) Add this configuration to a task group

Right now you could go to your terminal and type grunt uglify but we’ll need task groups to run multiple tasks later on. We have the default task empty, just waiting for something to be added so let’s modify it to the following:

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

At this stage your should be able to go to the terminal, type grunt and see the minification take place. Don’t forget to create a scripts.js file of course!

That didn’t take a lot of time to set up did it? Even if you’re new to all this and it took you some time to work through the steps, the time it saves will surpass time spent on it within a few uses.

Concatenating Files

Let’s look at concatenating files and learn how to specify multiple files as a target along the way.

Concatenation is the process of combining the contents of multiple files into a single file. We’ll need the grunt-contrib-concat plugin. Let’s work through the steps:

To install the plugin use npm install grunt-contrib-concat --save-dev in the terminal. Once done, make sure to add it to your Gruntfile just like before using grunt.loadNpmTasks('grunt-contrib-concat');.

Next up is the configuration. Let’s combine three specific files, the syntax will be familiar.

 concat: { dist: { src: ['dev/js/header.js', 'dev/js/myplugin.js', 'dev/js/footer.js'], dest: 'js/scripts.js', }, }, 

The code above takes the three files given as the source and combines them into the file given as the destination.

This is already pretty powerful but what if a new file is added? Do we need to come back here all the time? Of course not, we can specify a whole folder of files to concatenate.

 concat: { dist: { src: 'dev/js/*.js''], dest: 'js/scripts.js', }, }, 

Now, any javascript file within the dev/js folder will be merged into one big file: js/scripts.js, much better!

Now it’s time to create a task so we can actually concatenate some files.

 grunt.registerTask('mergejs', ['concat'] ); 

This is not the default task anymore so we’ll need to type its name in the terminal when we issue the grunt command.

 grunt mergejs 

Automating Our Automation

We’ve already made a lot of progress but there’s more! For now, when you want to concatenate or minify you need to go to the terminal and type the appropriate command. It’s high time we take a look at the watch command which will do this for us. We’ll also learn how to execute mulitple tasks at once, along the way.

To get going we’ll need to grab grunt-contrib-watch. I’m sure that you can install it and add it to the Gruntfile on yuor own by now, so I’ll start by showing you what I use in my test project.

 watch: { scripts: { files: ['dev/js/*.js'], tasks: ['concat', 'uglify'], }, } 

I named a set of files to watch “scripts”, just so I know what it does. Within this object I have specified files to watch and tasks to run. In the previous concatenation example we pulled together all the files in the dev/js directory.

In the minification example we minified this file. It makes sense to watch the dev/js folder for changes and run these tasks whenever there are any.

As you can see, multiple tasks can be called easily by separating them with commas. They will be performed in sequence, first the concatenation, then the minification in this case. This can also be done with task groups, which is kind of why they exist.

We can now modify our default task:

 grunt.registerTask('default', ['concat', 'uglify'] ); 

Now we have two choices. Whenever you want to concatenate and minify your scripts you can switch to the terminal and type grunt. You can also use the watch command to initiate the watching of your files: grunt watch.

It will sit there, waiting for you to modify these files. Once you do, it will perform all tasks assigned to it, go ahead, give it a try.

That’s much better, no input needed from us. You can now work away with your files and everything will be nicely done for you.


With that rudimentary knowledge of how plugins can be installed and used and how the watch command works, you are all set to become an automation addict yourself. There is a lot more to Grunt than what we discussed but nothing you couldn’t handle on your own.

Using commands for compiling SASS, optimizing images, autoprefixing, and more is just a matter of following the steps we discussed and reading the syntax the plugin requires.

If you know of some particularly great uses for Grunt please let us know in the comments, we’re always interested to hear how you use tools like Grunt!

Leave a Comment