Skip to content


This extension integrates voidlabs/mosaico with CiviCRM. Like CiviCRM, the main body of this extension is built on PHP, MySQL, and AngularJS. You can generally develop updates to the extension in a regular CiviCRM environment.

There are a few important exceptions and additions: the stylesheets (./sass, ./css) and the editor (voidlabs/mosaico). If you wish to develop patches for these, then it will require additional tools and processes.


  • Basic Development
  • Stylesheet Development and Editor Development
    • nodejs (Currently the mosaico build script only works with node v8 and older. You can use nvm to use multiple versions of nodejs. Eg. nvm install 8 && nvm use 8)
    • npm
    • grunt-cli
    • shoreditch (recommended)

Basic Development

The process is similar to many CiviCRM extensions:

## Navigate to your extension directory, e.g.
cd sites/default/files/civicrm/ext

## Download the extensions
git clone

## Download additional dependencies
composer install

## Enable the extension via web UI or CLI, e.g.
cv en mosaico

At this point, you can iteratively develop patches. Submit proposed updates via Github pull-requests.

Stylesheet Development

This project depends on sass and also on the shoreditch theme to compile its CSS.

Before you can compile the CSS you need to do the following from within this extension's directory:

npm install
git clone

You can then compile the Sass from sass/, recreating files in css/ like this:


Once you are done making your changes, please use BackstopJS (see Testing to check for any possible visual regression issues.

Commit changes for both SCSS and CSS. Submit proposed updates via Github pull-requests.

Editor Development

The CiviCRM extension ( depends on the editor (mosaico), which is an independent project. The mosaico component has its own requirements and workflows. uses a pre-built copy of mosaico (./packages/mosaico), so you may work on without needing to understand mosaico development. However, if you are doing development for both, then there are a few important details:

  • Using mosaico.git in the extension: You may replace the pre-built folder (./packages/mosaico) with a git repo. The extension specifically uses a fork ( with a few small patches. Typical setup steps:
    ## Remove pre-built copy of mosaico
    rm -rf packages/mosaico
    ## Download git repo
    git clone -b v0.15-civicrm-2
    ## Build
    cd packages/civicrm
    npm install
    grunt build
  • Branching for mosaico.git: The civicrm/mosaico fork follows the Twigflow (Rebase) pattern. You will notice additional branches such as v0.15-civicrm-2 (a branch derived from v0.15 for use by civicrm; it is the second major variant of the branch).
  • Tagging for mosaico.git: If there has been an update to mosaico.git, then you should make a new tag (eg v0.15-civicrm-2.1). Github will generate a pre-built package for the new version.
  • Updating the dependency: If there is a newer build of mosaico, then you may edit ./composer.json and update the the extra: downloads configuration.
    vi composer.json
    composer update --lock


The script bin/ handles various build activities:

## Download dependencies
./bin/ -D

## Regenerate DAOs
./bin/ -g

## Build zip archive
./bin/ -z

Addendum: Publication

Whenever a change is merged or pushed to, a bot on jenkins test-ci automatically builds a new zip archive and publishes

The build/publish process has a few properties:

  • It combines, civicrm/mosaico, and any other runtime dependencies into one zip file.
  • The version number is determined by reading info.xml (<version>) and appending the current Unix timestamp.
  • Example: If the version is declared as 1.0.beta1, then it will be published as 1.0.beta1.1478151288.
  • Three files are published:
  • The zip archive
  • The new info.xml file
  • A JSON document describing the build.
  • An alias is provided under the folder latest.

The bot does not publish the new version to To do this, download the to get the version from the info.xml ( eg. 2.5.1597918155).

Then add the actual release zip file to the release node on

Example filename:

Currently you should trigger manually the following hooks:

  • - this triggers the release process on, generates the unpublished release node and sends an email with a link to that node.
  • - this forces an update of the mosaico docs