A Magento2 Frontend Workflow

Using Grunt, LESS, NPM, and Yarn, you can make quick, iterative changes to your LESS files that LiveReload in the browser.

This short tutorial assumes you have Magento2 installed and ready to go. I’m using a local install on OSX, but these same commands and principles will work if you install Mage2 via Docker or Vagrant, as well.

Note: for a visual dive into this subject, check out the YouTube video I made on the subject, A Magento2 Frontend Workflow.

Magento2 ships with LESS because its easy to use PHP to compile LESS into CSS. When they made that architectural decision, there was no PHP SCSS implementation. Mage2 aims to have as few requirements as possible, however, so they want to ensure you can run Magento on a standard LAMP box.

But you can’t really do quick changes if you need Mage2 to compile your static assets. The php bin/magento setup:static-content:deploy command takes minutes to compile.

So to increase the development speed, Mage2 ships with a Grunt build process for those who want to take advantage of it.

Requirements for the Grunt Tools

  • Node
  • NPM

Make sure your local box has Node installed — when you install it, you will also have NPM.

Step 1: Install Yarn and Grunt

Just use Yarn instead of NPM to manage your dependencies. Seriously. It’s much faster than NPM, and is intended to be a drop-in replacement for it.

npm install -g yarn will install Yarn globally for you via NPM. Then, use Yarn to install Grunt globally via yarn global add grunt.

This will take a few minutes.

Step 2: Install the Mage2 Node Dependencies

In your Magento2 main directory (your-project/magento2) you should see a file named package.json.sample. This is the file that tells node what dependencies you need to run the applications contained therein.

Bring your command line into that directory (e.g., cd your-project/magento2).

Rename the file from package.json.sample to package.json, using a command like mv package.json.sample package.json.

Now, you’re ready to install the node dependencies! Do so by typing yarn in the command line from your your-project/magento2 directory.

Let that run. It will take a few minutes to process, as yarn is working to install and link together node dependencies that it will place in the your-project/magento2/node_modules folder.

Congrats! You’re setup. Test it by running the command yarn grunt clean. If it runs without errors, you’re ready to start.

(Optional) Step 3: Add your custom theme to the Grunt configuration

Off the bat, you should be good to go. But if you’re working with a template that isn’t the default one, you will need to add your theme to the Grunt configuration. In your-project/magento2/dev/tools/grunt/configs/ folder, edit the themes.js file.

This file exports configuration of all of the themes that Grunt is aware of. Add a configuration option for your theme so that the file looks something like:

 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.

'use strict';

 * Define Themes
 * area: area, one of (frontend|adminhtml|doc),
 * name: theme name in format Vendor/theme-name,
 * locale: locale,
 * files: [
 * 'css/styles-m',
 * 'css/styles-l'
 * ],
 * dsl: dynamic stylesheet language (less|sass)
module.exports = {

    mytheme: {
        area: 'frontend',
        name: 'YourProject/Theme',
        locale: 'en_US',
        files: [ 'your/theme/CSS' ],
        dsl: 'less'

    blank: {
        area: 'frontend',
        name: 'Magento/blank',
        locale: 'en_US',
        files: [
        dsl: 'less'
    luma: {
        area: 'frontend',
        name: 'Magento/luma',
        locale: 'en_US',
        files: [
        dsl: 'less'
    backend: {
        area: 'adminhtml',
        name: 'Magento/backend',
        locale: 'en_US',
        files: [
        dsl: 'less'

Your theme should be in the namespace called YourProject, under the directory your-project/magento2/app/design/frontend/Theme. Modify the above configuration if your template is located elsewhere. For more information on how to create themes, checkout the official Magento2 docs on theming.

Now, you should be able to run any of the commands below with your custom theme specified. E.g., yarn grunt clean:mytheme.


You now have a set of commands you can use that are quicker to execute and will help you develop your theme far quicker than using Mage2’s PHP CLI tools.


yarn grunt clean[:your-theme]

Cleans the your-project/magento2/pub/static directory of existing moved and/or symlinked assets that Magento2 will serve on page visits.

Note: you probably won’t need to run this command much. Use the next one instead.


yarn grunt exec[:your-theme]

Cleans the static directory of existing assets and recreates them based on the current file system.

This command is essential. If ever you add new LESS files, Grunt won’t actually be able to know about them until you re-run this command so that it pulls LESS files from your theme folder into the pub/static directory.


yarn grunt less[:your-theme]

Compiles the LESS files that Grunt finds in the pub/static directory from the entry points defined in your your-project/magento2/dev/tools/grunt/configs/themes.js directory.


yarn grunt watch

Watches your pub/static directory for changes in files (which are replicated over the symlinks to your theme directory), then recompiles the LESS files.

In addition, this command runs a LiveReload server, so if you have a browser extension for LiveReload, this command will push new changes live to the browser.


LiveReload isn’t working.

It can be a be tricky to get going right. There’s a specific order you need to run the Grunt commands in to get your LiveReload working (somewhat) consistently:

yarn grunt exec && yarn grunt less && yarn grunt watch

If you don’t do it this way, you may forget to compile your LESS files in the pub/static directory, so when you load the page, Mage2 will compile it for you. This will throw off the LiveReloader for some reason. Just stop your yarn grunt watch command and run the above string of commands.

I added a LESS file and @imported it, but it’s not showing up?

Because Grunt creates symlinks to individual files, and not full directories, if you create new LESS files, you have to rerun yarn grunt exec && yarn grunt less && yarn grunt watch (the yarn grunt exec being critical here) to have that file appear in the directory that Grunt watches.

Sidenote: Grunt symlinks individual files instead of directories for a good reason. If it did the full theme directory, Grunt would compile the CSS and spit it back out to your actual theme folder.

How does all of this work?

I could write it up, but instead I made a video. For a deeper explanation of what Grunt is doing here, check out the YouTube video I made on the subject, A Magento2 Frontend Workflow.