---
title: Inferred Tasks (Project Crystal)
description: Learn how Nx plugins automatically infer tasks from tool configurations, enabling caching, task dependencies, and optimized execution without manual setup.
sidebar:
  order: 1
filter: 'type:Concepts'
---

In Nx version 18, Nx plugins can automatically infer tasks for your projects based on the configuration of different tools. Many tools have configuration files which determine what a tool does. Nx is able to cache the results of running the tool. Nx plugins use the same configuration files to infer how Nx should [run the task](/docs/features/run-tasks). This includes [fine-tuned cache settings](/docs/features/cache-task-results) and automatic [task dependencies](/docs/concepts/task-pipeline-configuration).

For example, the `@nx/webpack` plugin infers tasks to run webpack through Nx based on your repository's webpack configuration. This configuration already defines the destination of your build files, so Nx reads that value and caches the correct output files.

{% youtube
src="https://youtu.be/wADNsVItnsM"
title="Project Crystal"
/%}

## How does a plugin infer tasks?

Every plugin has its own custom logic, but in order to infer tasks, they all go through the following steps.

### 1. detect tooling configuration in workspace

The plugin will search the workspace for configuration files of the tool. For each configuration file found, the plugin will infer tasks. i.e. The `@nx/webpack` plugin searches for `webpack.config.js` files to infer tasks that run webpack.

### 2. create an inferred task

The plugin then configures tasks with a name that you specified in the plugin's configuration in `nx.json`. The settings for the task are determined by the tool configuration.

The `@nx/webpack` plugin creates tasks named `build`, `serve` and `preview` by default and it automatically sets the task caching settings based on the values in the webpack configuration files.

## What is inferred

Nx plugins infer the following properties by analyzing the tool configuration.

- Command - How is the tool invoked
- [Cacheability](/docs/concepts/how-caching-works) - Whether the task will be cached by Nx. When the Inputs have not changed the Outputs will be restored from the cache.
- [Inputs](/docs/guides/tasks--caching/configure-inputs) - Inputs are used by the task to produce Outputs. Inputs are used to determine when the Outputs of a task can be restored from the cache.
- [Outputs](/docs/guides/tasks--caching/configure-outputs) - Outputs are the results of a task. Outputs are restored from the cache when the Inputs are the same as a previous run.
- [Task Dependencies](/docs/concepts/task-pipeline-configuration) - The list of other tasks which must be completed before running this task.

## Nx uses plugins to build the graph

A typical workspace will have many plugins inferring tasks. Nx processes all the plugins registered in `nx.json` to create project configuration for individual projects and a project and task graph that shows the connections between them all.

### Order matters

Plugins are processed in the order that they appear in the `plugins` array in `nx.json`. So, if multiple plugins create a task with the same name, the plugin listed last will win. If, for some reason, you have a project with both a `vite.config.js` file and a `webpack.config.js` file, both the `@nx/vite` plugin and the `@nx/webpack` plugin will try to create a `build` task. The `build` task that is executed will be the task that belongs to the plugin listed lower in the `plugins` array.

Nx hashes the project graph node produced by each plugin to determine whether cached task results can be reused. If your plugin's `createNodes`/`createNodesV2` function returns different output on different runs or machines, Nx will compute a different hash and treat unchanged code as a cache miss. Keep output stable by following two rules:

- **Sort arrays deterministically.** The order of `targets`, `inputs`, `outputs`, `dependsOn`, and `metadata.targetGroups` entries must be the same every time—sort them explicitly before returning.
- **Avoid machine-specific or run-specific values.** Do not leak `process.env` variables, absolute paths, timestamps, or random IDs into target configuration. Prefer workspace-relative tokens (e.g. `{workspaceRoot}`) over absolute paths.

### Scope plugins to specific projects

Plugins use config files to infer tasks for projects. You can specify which config files are processed by Nx plugins using the `include` and `exclude` properties in the plugin configuration object.

```jsonc
// nx.json
{
  "plugins": [
    {
      "plugin": "@nx/jest/plugin",
      "include": ["packages/**/*"],
      "exclude": ["**/*-e2e/**/*"],
    },
  ],
}
```

The `include` and `exclude` properties are file glob patterns that filter which configuration files the plugin processes. In the example above, the `@nx/jest/plugin` will only infer tasks for projects where the `jest.config.ts` file path matches the `packages/**/*` glob but does not match the `**/*-e2e/**/*` glob.

This is useful when you want a plugin to only affect certain projects, or when you need to apply different plugin options to different sets of projects by registering the same plugin multiple times with different `include`/`exclude` patterns.

## View inferred tasks

To view the task settings for projects in your workspace, [show the project details](/docs/features/explore-graph) either from the command line or using Nx Console.

```shell
nx show project my-project --web
```

{% project_details%}

```json
{
  "project": {
    "name": "myreactapp",
    "type": "app",
    "data": {
      "root": "apps/myreactapp",
      "targets": {
        "build": {
          "options": {
            "cwd": "apps/myreactapp",
            "command": "vite build"
          },
          "cache": true,
          "dependsOn": ["^build"],
          "inputs": [
            "production",
            "^production",
            {
              "externalDependencies": ["vite"]
            }
          ],
          "outputs": ["{workspaceRoot}/dist/apps/myreactapp"],
          "executor": "nx:run-commands",
          "configurations": {},
          "metadata": {
            "technologies": ["vite"]
          }
        },
        "serve": {
          "options": {
            "cwd": "apps/myreactapp",
            "command": "vite serve",
            "continuous": true
          },
          "executor": "nx:run-commands",
          "configurations": {},
          "metadata": {
            "technologies": ["vite"]
          }
        },
        "preview": {
          "options": {
            "cwd": "apps/myreactapp",
            "command": "vite preview"
          },
          "executor": "nx:run-commands",
          "configurations": {},
          "metadata": {
            "technologies": ["vite"]
          }
        },
        "serve-static": {
          "executor": "@nx/web:file-server",
          "options": {
            "buildTarget": "build",
            "continuous": true
          },
          "configurations": {}
        },
        "test": {
          "options": {
            "cwd": "apps/myreactapp",
            "command": "vitest run"
          },
          "cache": true,
          "inputs": [
            "default",
            "^production",
            {
              "externalDependencies": ["vitest"]
            }
          ],
          "outputs": ["{workspaceRoot}/coverage/apps/myreactapp"],
          "executor": "nx:run-commands",
          "configurations": {},
          "metadata": {
            "technologies": ["vite"]
          }
        },
        "lint": {
          "cache": true,
          "options": {
            "cwd": "apps/myreactapp",
            "command": "eslint ."
          },
          "inputs": [
            "default",
            "{workspaceRoot}/.eslintrc.json",
            "{workspaceRoot}/apps/myreactapp/.eslintrc.json",
            "{workspaceRoot}/tools/eslint-rules/**/*",
            {
              "externalDependencies": ["eslint"]
            }
          ],
          "executor": "nx:run-commands",
          "configurations": {},
          "metadata": {
            "technologies": ["eslint"]
          }
        }
      },
      "name": "myreactapp",
      "$schema": "../../../node_modules/nx/schemas/project-schema.json",
      "sourceRoot": "apps/myreactapp/src",
      "projectType": "application",
      "tags": [],
      "implicitDependencies": [],
      "metadata": {
        "technologies": ["react"]
      }
    }
  },
  "sourceMap": {
    "root": ["apps/myreactapp/project.json", "nx/core/project-json"],
    "targets": ["apps/myreactapp/project.json", "nx/core/project-json"],
    "targets.build": ["apps/myreactapp/vite.config.ts", "@nx/vite/plugin"],
    "targets.build.command": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.build.options": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.build.cache": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.build.dependsOn": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.build.inputs": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.build.outputs": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.build.options.cwd": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.serve": ["apps/myreactapp/vite.config.ts", "@nx/vite/plugin"],
    "targets.serve.command": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.serve.options": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.serve.options.cwd": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.preview": ["apps/myreactapp/vite.config.ts", "@nx/vite/plugin"],
    "targets.preview.command": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.preview.options": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.preview.options.cwd": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.serve-static": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.serve-static.executor": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.serve-static.options": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.serve-static.options.buildTarget": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.test": ["apps/myreactapp/vite.config.ts", "@nx/vite/plugin"],
    "targets.test.command": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.test.options": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.test.cache": ["apps/myreactapp/vite.config.ts", "@nx/vite/plugin"],
    "targets.test.inputs": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.test.outputs": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.test.options.cwd": [
      "apps/myreactapp/vite.config.ts",
      "@nx/vite/plugin"
    ],
    "targets.lint": ["apps/myreactapp/project.json", "@nx/eslint/plugin"],
    "targets.lint.command": [
      "apps/myreactapp/project.json",
      "@nx/eslint/plugin"
    ],
    "targets.lint.cache": ["apps/myreactapp/project.json", "@nx/eslint/plugin"],
    "targets.lint.options": [
      "apps/myreactapp/project.json",
      "@nx/eslint/plugin"
    ],
    "targets.lint.inputs": [
      "apps/myreactapp/project.json",
      "@nx/eslint/plugin"
    ],
    "targets.lint.options.cwd": [
      "apps/myreactapp/project.json",
      "@nx/eslint/plugin"
    ],
    "name": ["apps/myreactapp/project.json", "nx/core/project-json"],
    "$schema": ["apps/myreactapp/project.json", "nx/core/project-json"],
    "sourceRoot": ["apps/myreactapp/project.json", "nx/core/project-json"],
    "projectType": ["apps/myreactapp/project.json", "nx/core/project-json"],
    "tags": ["apps/myreactapp/project.json", "nx/core/project-json"]
  }
}
```

{% /project_details %}

## Overriding inferred task configuration

You can override the task configuration inferred by plugins in several ways.
If you want to overwrite the task configuration for multiple projects, [use the `targetDefaults` object](/docs/reference/nx-json#target-defaults) in the `nx.json` file.
If you only want to override the task configuration for a specific project, [update that project's configuration](/docs/reference/project-configuration) in `package.json` or `project.json`.
This configuration is more specific so it will override both the inferred configuration and the `targetDefaults`.

The order of precedence for task configuration is:

1. Inferred Task Configurations from plugins in `nx.json`.
2. `targetDefaults` in `nx.json`.
3. Project Configuration in `package.json` or `project.json`.

More details about how to override task configuration is available in these guides:

- [Configure Inputs for Task Caching](/docs/guides/tasks--caching/configure-inputs)
- [Configure Outputs for Task Caching](/docs/guides/tasks--caching/configure-outputs)
- [Defining a Task Pipeline](/docs/guides/tasks--caching/defining-task-pipeline)
- [Pass Arguments to Commands](/docs/guides/tasks--caching/pass-args-to-commands)

## Existing Nx workspaces

{% aside type="tip" title="Learn by doing" %}
Try the [Reducing Configuration Boilerplate](/docs/getting-started/tutorials/reducing-configuration-boilerplate) tutorial to apply these concepts in your own workspace.
{% /aside %}

If you have an existing Nx Workspace and upgrade to the latest Nx version, a migration will automatically set `useInferencePlugins` to `false` in `nx.json`. This property allows you to continue to use Nx without inferred tasks.

When `useInferencePlugins` is `false`:

1. A newly generated project will have all targets defined with executors - not with inferred tasks.
2. Running `nx add @nx/some-plugin` will not create a plugin entry for `@nx/some-plugin` in the `nx.json` file. (So that plugin will not create inferred tasks.)

If you want to **migrate** your projects to use inferred tasks, follow the recipe for [migrating to inferred tasks](/docs/guides/tasks--caching/convert-to-inferred).

Even once a repository has fully embraced inferred tasks, `project.json` and executors will still be useful. The `project.json` file is needed to modify inferred task options and to define tasks that can not be inferred. Some executors perform tasks that can not be accomplished by running a tool directly from the command line (i.e. batch mode).
