Creating a Gruntfile.js
Learn the structure and anatomy of a Gruntfile.js — the wrapper function, config object, plugin loading, and task registration.
Creating a Gruntfile.js
The Gruntfile.js is the heart of your Grunt workflow. It is where you configure tasks, load plugins, and register custom commands. Every Grunt project needs one in the project root. In this episode you will learn the anatomy of a Gruntfile and create your first one.
The Basic Gruntfile Structure
module.exports = function(grunt) {
// 1. Configure tasks
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
// Task configurations go here
});
// 2. Load plugins
// grunt.loadNpmTasks('plugin-name');
// 3. Register tasks
grunt.registerTask('default', []);
};
Anatomy of a Gruntfile
Every Gruntfile has three main sections wrapped inside the module.exports function:
| Section | Purpose | Method |
|---|---|---|
| Configuration | Define how each task should run (inputs, outputs, options) | grunt.initConfig({}) |
| Plugin Loading | Load installed Grunt plugins so their tasks are available | grunt.loadNpmTasks() |
| Task Registration | Create named commands that run one or more tasks | grunt.registerTask() |
The Wrapper Function
module.exports = function(grunt) {
// All Grunt code goes inside this function
};
The entire Gruntfile is wrapped in a module.exports function. This is a Node.js module pattern — Grunt requires this file and passes the grunt object which provides all the API methods you need.
grunt.initConfig — Configuration
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concat: {
options: {
separator: ';\n',
},
dist: {
src: ['src/js/*.js'],
dest: 'dist/js/bundle.js',
},
},
});
The initConfig object contains a property for each task. Each task property matches the plugin name (e.g., concat for grunt-contrib-concat). Inside each task, you define targets, options, source files, and destination files.
Understanding the pkg Property
pkg: grunt.file.readJSON('package.json')
This reads your package.json into a variable. You can then reference project metadata in your configuration using template strings like <%= pkg.name %> and <%= pkg.version %>. This is useful for adding banners or naming output files dynamically.
Task Configuration Structure
taskName: {
options: {
// Global options for this task
},
targetName: {
options: {
// Target-specific options (override global)
},
src: ['source/files/**/*.js'],
dest: 'output/file.js',
},
anotherTarget: {
src: ['other/**/*.js'],
dest: 'other-output.js',
},
}
| Property | Purpose |
|---|---|
options | Configuration options for the task (top level) or target (nested level) |
targetName | A named sub-task — you can have multiple targets per task |
src | Input files — supports glob patterns like *.js and **/*.js |
dest | Output file or directory |
Glob Patterns for File Matching
| Pattern | Matches |
|---|---|
*.js | All .js files in the current directory |
**/*.js | All .js files in any subdirectory (recursive) |
src/js/*.js | All .js files in src/js/ |
!src/js/vendor.js | Exclude a specific file (prefix with !) |
['a.js', 'b.js'] | Specific files in order |
grunt.loadNpmTasks — Loading Plugins
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-sass');
Each plugin you install must be explicitly loaded with loadNpmTasks. This registers the plugin's tasks so they can be used in your configuration and run from the command line.
grunt.registerTask — Custom Commands
// Register the default task (runs when you type just "grunt")
grunt.registerTask('default', ['concat', 'uglify', 'sass']);
// Register a named task
grunt.registerTask('build', ['concat', 'uglify']);
// Register a task that runs a single plugin task
grunt.registerTask('styles', ['sass']);
Registered tasks are the commands you type in the terminal. grunt default (or just grunt) runs the default task. grunt build runs the build task. Each registered task specifies an array of plugin tasks to run in order.
Running Tasks
# Run the default task
grunt
# Run a specific registered task
grunt build
# Run a specific plugin task
grunt concat
# Run a specific target of a task
grunt concat:dist
A Complete Starter Gruntfile
module.exports = function(grunt) {
// 1. Configuration
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
// Placeholder — tasks will be added in next episodes
});
// 2. Load plugins
// (none yet — we'll add them in the next episodes)
// 3. Register default task
grunt.registerTask('default', []);
};
Save this as Gruntfile.js in your project root. Running grunt in the terminal should now work without errors — it just does nothing yet because we have not added any plugins.
Testing Your Gruntfile
grunt
If everything is set up correctly, you will see:
Done, without errors.
If you see an error like "Unable to find local grunt," make sure you ran npm install grunt --save-dev. If you see "Cannot find module," check that your Gruntfile.js is in the project root directory.
Key Takeaways
- Every Gruntfile is a
module.exportswrapper function that receives thegruntobject - Three sections:
initConfig(configure tasks),loadNpmTasks(load plugins),registerTask(create commands) - Task configurations match plugin names and can have multiple targets
pkg: grunt.file.readJSON('package.json')provides access to project metadata- Glob patterns (
*.js,**/*.js) specify source files flexibly - The
defaulttask runs when you typegruntwithout arguments