Publish affected Projects with custom Nx commands

With custom Nx commands it becomes very easy to publish multiple projects that are affected by changes. In this post I'm going to show you how to achieve that.

Nx Generators & Executors

Nx helps you to manage projects in monorepos by providing generators and executors. Generators, as the name implies, are used to generate boilerplate code or configuration. So with generators you can for example easily create new Angular libraries or components. Executors on the other hand, are used to build or test the code inside a monorepo.

By default, Nx comes with the ability to calculate which projects of a monorepo are affected by changes. It does so by building a dependency graph of all the projects in a monorepo. It then uses Git to check which files have actually changed. Based on the dependency graph and the changed files it knows which projects are affected by changes, and it can then execute its executors on only those projects and its dependents. This means that by default, Nx only builds or tests the projects that have actually changed, reducing build times to a minimum.

This concept is not only limited to testing and building of projects. Nx ships with many other executors by default, and there are even more provided by 3rd party plugins. And of course you can also implement your own executors. But there is also another way to use this infrastructure, and it is even easier to use it: Custom Nx commands.

With custom Nx commands you don't need to implement your own executor. You can simply specify a shell command as part of the Nx workspace configuration and a generic executor will take care of the execution of the command. So if you have any custom command that needs to be executed in your build pipeline you can make use of Nx to only execute that command on projects affected by changes.

Publish a Project with a custom Command

Before we can create a custom Nx command, we first need to know which command we have to execute. Given the build output of our library is located in dist/packages/my-library the command to publish the library with Yarn is:

1
yarn publish dist/packages/my-library

Now we need add a target in the Nx workspace configuration (which is either in the file angular.json or workspace.json, depending on our setup) that specifies the custom command we want to execute:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "my-library": {
    "architect": {
      "publish": {
        "builder": "@nrwl/workspace:run-commands",
        "options": {
          "command": "yarn publish dist/packages/my-library"
        }
      }
    }
  }
}

On line 4 you can see the name of our new target, in this case publish. We need to specify that name when we want to execute our custom command with Nx. On the next line we specify the executor that is used to execute the target. As mentioned before, we use the generic executor @nrwl/workspace:run-commands that is able to execute any shell command. Finally, on line 7 we specify the command we want to execute. You can find more options that can be configured for custom commands in the Nx documentation about custom commands.

That's all we have to do. We can now execute our command with Nx:

1
nx run my-library:publish

Publish affected Projects only

So far we have not generated any benefit. We just replaced on command with another one. To use the full potential of Nx we need to add this custom target to every project in our monorepo. That's were generators would come in handy. With a generator we would be able to create a template and add the same configuration to all projects with very little effort. But generators are a topic for another time. So for now let's just assume that we added the same target to all our projects inside the monorepo.

We can now use the following command to only execute our publish target on projects affected by changes:

1
nx affected --target publish

This allows us to use the same command within our build pipeline to publish only the projects that were affected by changes. Combined with the Nx executors for building and testing we can reduce the runtime of our pipeline to the bare minimum.