🧙‍♂️ New course! Magento 2 Router Wizardry

Learn more

Set up & configure Grunt for Magento 2 theming

Getting your developing tooling is important for efficient Magento 2 theming, and a crucial part of that process is setting up & configuring Grunt for LESS & CSS compilation.

Mark Shust

Mark Shust

Last Updated 5 min read

What is Grunt?

Grunt is an automator that performs repetitive tasks for you such as minifcation, compilation, unit testing, linting, etc. It is similar to a lot of other tools out there such as Gulp, Webpack & Vite.

Grunt logo

Normally when you write CSS, a task runner is not needed. But Magento uses Less, which extends CSS to add support for variables, mixins, nesting, math operations, functions & more.

Less.js is a JavaScript compiler tool that converts this special Less code to standard CSS code. You’ll need a task runner to accomplish this, and Grunt supports Less compilation, and is already built into Magento.

Less logo


Before continuing, if you are using docker-magento, all of these steps have already been taken care of for you! All you need to do is run bin/setup-grunt, and the installation & configuration of Grunt is magically done for you.

You can skip ahead to the Run Grunt commands section if you wish, just remember to prefix grunt with bin/ to use Grunt within the Docker container. But if you’d like to know how the Grunt setup works, just keep following along.

Install Grunt

Assuming we already have Node.js installed on our machine, we can install the grunt command line globally with:

npm install -g grunt-cli

Before running grunt, we’ll also need to install some prerequisite packages. Magento comes with a few files in the root of your project:

  • package.json.sample
  • Gruntfile.js.sample
  • grunt-config.js.sample

We’ll need to copy all of these files to the same locations, but without the .sample suffix.

cp package.json.sample package.json
cp Gruntfile.js.sample Gruntfile.js
cp grunt-config.js.sample grunt-config.js

After doing so, all NPM dependencies can be installed with:

npm install

This looks at the package.json file that we just created, and installs all dependencies in that file.

Configure Grunt for Magento

Grunt works from a Gruntfile, which is basically a configuration file that contains a function with a list of instructions that Grunt executes. If we take a look at this file in the root of our Magento folder, we’ll see that it contains a lot of configuration and tooling to get it working with Magento.

Now let’s open up the grunt-config.js file. This file defines the location to look for to find the theme configuration file.

Notice that it is set to:

  "themes": "dev/tools/grunt/configs/local-themes"

This value is just fine, but we need to create this file. We’ll do that by going to the dev/tools/grunt/configs directory. This directory contains files that will define all core Magento tasks that Grunt will execute.

We’ll go ahead and create that local-themes file. Let's do that by copying the themes.js file in this directory over to local-themes.js. This safesguards any changes we make, so they don’t get overridden by core updates.

Run Grunt commands

At this point, Grunt can be executed. We can do this by running grunt from the command line. If you are running docker-magento, be sure to prefix the command with a bin/.

When you run this command, it executes the function exported from the Gruntfile, which isn’t particularly useful at the moment.

Let’s go back to the dev/tools/grunt/configs folder, and we’ll see some other files in here such as clean, exec, and so on. Each of these files exports a function that is executed when the related name is passed to grunt.

Here is a list of common Grunt actions that are used in Magento frontend development, and when to use each:

grunt cleanRemoves all theme related static files in the pub/static and var/view_preprocessed directories.
grunt execRuns grunt clean, but also creates symlinks and all related directories for Less source files within the pub/static and var/view_preprocessed directories. You can also use grunt exec:<theme> to do this only for a specific theme.
grunt lessCompiles Less files into CSS files using the symlinks that were generated from the grunt exec command. You can also use grunt less:<theme> to do this only for a specific theme.
grunt watchTracks the changes in the source files, recompiles CSS files, and reloads the page in the browser.

Open up clean.js to look at an example. This file loads the themes, which for us comes from that local-themes.js file, and sets some config values for each theme.

It then defines some more configuration that tells Grunt what to do for each of these themes.

Let’s execute:

grunt clean

This command essentially purges all view caches in Magento, for each of those defined themes. Pretty neat, right?

Now, let's run:

grunt exec

This command will take quite a bit longer to run, and that’s because besides running the clean command for each theme, it also compiles all of the related styles for each Magento theme. There’s a lot of magic going on behind the scenes that we’ll get to later.

We can also execute tasks for a specific theme by typing a colon, followed by the name of the theme, such as:

grunt exec:luma

This will execute the grunt tasks, but only for the Luma theme.

If you wish to have Grunt automatically listen for changes to execute upon, you can do so with the watch command, which can be ran with:

grunt watch

Rather than making a stylesheet update and running grunt exec every time you update a file, you can have the Grunt script, standing by, watching for filesystem changes. When a file changes, Grunt will automatically run the related exec command, and just for that specific file. This makes styling way quicker and takes away some of the development burden when compiling styles.

Thrilled to level up in Magento? Explore these 3 options:

  1. Explore Magento 2 fundamentals & best practices course (1,000+ students)
  2. Grow your Magento expertise with all courses & lessons (700+ students)
  3. Learn visually with blocks of code & inline comments (3,000+ students)