Tearing Grunt Apart

Introducing Grunt v0.4

For the last nine months, I’ve been working with Ben and our team of fantastic contributors to modularize the Grunt codebase. Today, we’re happy to announce that Grunt v0.4 has been published to npm. Hold on to your hats, a lot has changed!

Architectural Improvements

The primary focus of this version can be summarized by the venerable words of Doug McIlroy, “Do one thing and do it well.” We’re proud to say that this release is a major milestone on the road to fully embracing the Unix philosophy.

Built In Tasks Removed

If you’re coming from Grunt v0.3.x, the most immediate difference you’ll notice is that we’ve removed all of the built-in tasks. Don’t worry, they aren’t gone—we’ve extracted them into officially maintained, standalone plugins. If you visit the plugin listing on our website, look for the entries with stars next to their names.

One of the biggest benefits of this change is faster iteration. It’s no longer necessary to ship a new version of Grunt for every minor plugin change! If jshint gets updated, for example, we can just release a new version of grunt-contrib-jshint.

Finally, with our core plugins separated, the barrier to entry for collaboration is lower than ever. If you’d like to get involved, please join us in #grunt on irc.freenode.net, or check out the Contributing guide and submit a pull request to add the feature you want.

A note about the “init” task

This scaffolding task was always an odd-duck, and it really deserves it’s own project. So, we’ve broken it into a separate npm module, grunt-init, which can be installed globally with npm install -g grunt-init. In the coming weeks, the Yeoman team will be replacing this task entirely, using their rails-inspired generator system. If you’ve authored templates for the init task, get in touch with them for details on how to make the conversion.

Global Installation

Another departure for those coming from Grunt v0.3.x is that Grunt itself no longer ships with a binary. Instead of installing Grunt globally, you now specify it as a development dependency in your project’s package.json file, along with any Grunt plugins you might be using.

In order to get the grunt command, we’ve provided the grunt-cli tool, which should be installed globally. The sole purpose of this tool is to load and run the locally installed version of Grunt, and good news—it will work with every version from 0.3x and higher.

There has been considerable confusion in the community about global vs local installation of packages. We recommend reading this excellent article by @isaacs for more information about why it is desirable to install things locally when using node.

Supercharging Grunt’s Declarative Power

Gruntfiles are now more powerful than ever. We’ve been hard at work implementing community requests, and thanks to everyone’s feedback, the results are fantastic. Here are a few of the major additions:

Options Merging

Need to run the same task on more than one set of files? Say goodbye to duplicative configuration, options can now be defined at the task level—they’ll automatically apply for all of your target file groups. If needed, you can override them individually. Check out our documentation for more details.

Mapping individual files from one location to another

We have a new syntax for this common request (e.g. compiling coffeescript files from one directory to javascript files in another, while maintaining the folder structure), it works with any v0.4 compatible plugin, and it eliminates reams of boilerplate for plugin authors. Check out our documentation for more details.

Templates everywhere

Need data from package.json for your build process? How about a YAML file? Not a problem, just load it into your configuration and apply it anywhere you like. Check out our documentation for more details.

New APIs

Just to whet your whistle, here are a few handy methods we’ve added to make writing tasks a cinch: file.isPathInCwd, file.doesPathContain & file.arePathsEquivalent. There are far too many additions to list in this introduction, please see our migration documentation for a full rundown.

New Website

Grunt 0.4 ships with a flashy new website. We’ve got reams of documentation, and helpful tools for discovering the perfect plugin for your project. Check it out at gruntjs.com!


If you think Grunt is great now, just wait until you see what we have in store for the next major version. Here’s a glimpse of what you can expect next:

Glob Expansion Library

Grunt has made it easier than ever to select, negate and map your project files from one location to another—complicated globbing patterns need not apply! We’re so happy with the power this system affords that we’re going to extract it into a standalone library so anyone can use it.

Configuration Library

Sharing values across multiple configuration files is a breeze with Grunt’s templating system. Soon, you’ll be able to unleash Grunt’s declarative power anywhere you need it—we’re turning this system to a standalone npm package as well.

Grunt Middleware

Don’t like Grunt’s configuration syntax? Go crazy and write a middleware to convert your format to ours. Maybe we’ll love it and decide to make it the default.

Escaping Dependency Hell

When you upgrade to v0.4, chances are strong you’ll run into some tasks that don’t support it yet. We know this sucks, and we’re working with plugin authors to get the ecosystem up to speed as quickly as possible. Long term, we’re going to solve this problem entirely. Here’s how:

Grunt v0.5 will ship with support for a new plugin format called node-task. It defines a stateless, promise-based, event emitting API that doesn’t depend on Grunt. It has a real-live spec, and the Grunt team is working with the front-end developer community in the hopes that compliant modules will be compatible with every task runner under the sun. When it’s done, it will ship with a test suite that anyone can use to build their own tasks.

Further reading

Phew, you made it to the end—thanks for hanging with me. If you’d like to know more about Grunt, please read our Getting Started Guide, and check out all of the ways you can configure your tasks, too.

Grunt on!


We moved off of Disqus for data privacy and consent concerns, and are currently searching for a new commenting tool.

  1. I’m assuming Grunt.js follows SEMVER (It doesn’t explicitly say but NPM uses SEMVER for it’s libraries).

    I’m also assuming that Grunt.js, based on it’s downloads and issue list, is used quite widely in development environments and is dependent upon by other libraries.

    If the latter is true then I’m also assuming that people can fix the problem Grunt.js sets out to solve.

    If all of these assumptions are true: Why in the world is Grunt.js still not version 1.0.0? What, other than passing the buck on issues and laziness, do you gain from pushing out another v0.* build? Why perpetuate a bad practice of absolutely ignoring SEMVER semantics?

      • That same rules set also says:

        > Version 1.0.0 defines the public API. The way in which the version number is incremented after this release is dependent on this public API and how it changes.

        Which you’ve defined a couple of times.

        > Minor version Y (x.Y.z | x > 0) MUST be incremented if new, backwards compatible functionality is introduced to the public API. It MUST be incremented if any public API functionality is marked as deprecated. It MAY be incremented if substantial new functionality or improvements are introduced within the private code. It MAY include patch level changes. Patch version MUST be reset to 0 when minor version is incremented.

        Which you’ve changed multiple times but with multiple breaking changes.

        You might also read the FAQ:

        > How do I know when to release 1.0.0?
        > If your software is being used in production, it should probably already be 1.0.0. If you have a stable API on which users have come to depend, you should be 1.0.0. If you’re worrying a lot about backwards compatibility, you should probably already be 1.0.0.

        Note the similarity to my assumptions.

        To pre-empt the reply I know I’m going to get about \”were changing things a lot!\”:

        > Doesn’t this discourage rapid development and fast iteration?
        > Major version zero is all about rapid development. If you’re changing the API every day you should either still be in version 0.x.x or on a separate development branch working on the next major version.

          • That’s great and all up until someone gets bit in the ass by bad versioning (Like I did) because they assumed the library was using SEMVER (Like NPM does).

            Then it’s not just something you can imagine away.

          • Kurtis,

            The only real question you asked was answered by Ben less than minute after you posed it. If you haven’t already tried creating issues when you run into problems with Grunt, please give it a shot. I think you’ll find the response time pretty impressive, especially for something you’re using at no cost.

            I’m sorry your experience with Grunt has left you feeling so vitriolic. It’s true, we’ve fumbled quite a bit with the versioning on this release. We’ll do our best to ensure it doesn’t happen again with 0.5.

            In the future, you may find people more receptive to your complaints if you make an effort to express them in a less inflammatory manner.

          • Tyler,

            I appreciate your measured and polite reply. I’m sorry if you felt I was being vitriolic towards you and I definitely should have been more tempered.

            My aggravation is with both the Ruby and JS community for ignoring the important parts of SEMVER semantics when our tools (npm and gem) depend on them so heavily and have made special operators (~>) just to abide by them.

            Sadly, problems that you would want me to make Issues for generally happen in libraries that depend on Grunt and are unwittingly targeting Grunt’s latest release (instead of only minor and bug releases for the version they built for).

            There is nothing that grunt can do without actively pushing grunt extension authors to specially respect the fact that Grunt.js doesn’t quite follow semantic versioning.

            Thanks for reply.

            post-script: I hope you’ll take notice that my initial reply was rather even, and only after seeing the same old arguments trotted out did I get annoyed. Still, I apologize for my aggressive maner.

          • Maybe one of these days he will find a project that needs someone to tell them everything they are doing wrong like a condescending dick.

Contact Us

We'd love to hear from you. Get in touch!


P.O. Box 961436
Boston, MA 02196