Project Inference

Experimental

This API is experimental and might change.

Project inference describes the ability of Nx to discover and work with projects based on source code and configuration files in your repo. Out of the box, Nx identifies projects based on the presence of package.json and project.json files. It also identifies targets in the package.json scripts and the project.json targets.

Project inference plugins allow you to extend this functionality of Nx to other languages and file structures.

Adding Plugins to Workspace

You can register a plugin by adding it to the plugins array in nx.json:

nx.json
1{ 2 ..., 3 "plugins": [ 4 "awesome-plugin" 5 ] 6} 7

Project File Patterns

Project file patterns are used in two scenarios:

  • Inferring projects
  • Determining which files should be passed into registerProjectTargets.

Let's use the below plugin and workspace layout as an example:

libs/awesome-plugin/index.ts
1export const projectFilePatterns = ['project.json', 'my-other-project-file']; 2export function registerProjectTargets(projectFilePath) { 3 console.log(projectFilePath); 4} 5

workspace layout

1my-workspace/ 2├─ node_modules/ 3├─ libs/ 4│ ├─ my-project/ 5│ │ ├─ my-other-project-file 6│ ├─ nx-project/ 7│ │ ├─ my-other-project-file 8│ │ ├─ project.json 9├─ nx.json 10└─ package.json 11 12

During initialization, we would expect to see "libs/my-project/my-other-project-file", "libs/nx-project/my-other-project-file", "libs/nx-project/project.json" all logged out to the console. Nx was able to infer my-project from the layout.

Implementing a Project Target Configurator

A project target configurator is a function that takes a path to a project file, and returns the targets inferred from that file.

Plugins should export a function named registerProjectTargets that infers the targets from each matching project file. This function receives the path to the project file as its sole parameter.

The registerProjectTargets function should return a Record<string, TargetConfiguration>, which describes the targets inferred for that specific project file.

1import { TargetConfiguration } from '@nx/devkit'; 2 3export const projectFilePatterns = ['project.json', 'my-other-project-file']; 4 5export function registerProjectTargets( 6 projectFilePath: string 7): Record<string, TargetConfiguration> { 8 return { 9 build: { 10 /** 11 * This object should look exactly like a target 12 * configured inside `project.json` 13 */ 14 }, 15 }; 16} 17
Nx 15 and lower use @nrwl/ instead of @nx/

Multiple Matches

It is possible that the registerProjectTargets function may be called multiple times for one project. This could occur in a few cases, one of which is demonstrated above.

  • One plugin may list multiple file patterns, and a project may match more than one of them.
  • Multiple plugins may list similar patterns, and pick up the project separately.

In the first case, the plugin that you are writing will be called into multiple times. If you return the same target (e.g. build) on each call, whichever is ran last would be the target that Nx calls into.

The order that the function would be called is NOT guaranteed, so you should try to avoid this when possible. If specifying multiple patterns, they should either be mutually exclusive (e.g. one match per project) or the plugin should conditionally add targets based on the file passed in.

In the second case, different plugins may attempt to register the same target on a project. If this occurs, whichever target was registered by the plugin listed latest in nx.json would be the one called into by Nx. As an example, assume plugin-a, plugin-b, and plugin-c all match a file and register build as a target. If nx.json included "plugins": ["plugin-a", "plugin-b", "plugin-c"], running nx build my-project would run the target as defined by "plugin-c".

Alternatively, if nx.json included "plugins": ["plugin-c", "plugin-b", "plugin-a"], running nx build my-project would run the target as defined by "plugin-a".

Development Tips

There is a cache that Nx uses to avoid recalculating the project graph as much as possible, but it may need to be skipped during plugin development. You can set the following environment variable to disable the project graph cache: NX_CACHE_PROJECT_GRAPH=false.

It might also be a good idea to ensure that the dep graph is not running on the nx daemon by setting NX_DAEMON=false, as this will ensure you will be able to see any console.log statements you add as you're developing. You can also leave the daemon active, but console.log statements would only appear in its log file.