A project's configuration is constructed by Nx from three sources:
- Tasks inferred by Nx plugins from tooling configuration
- Workspace
targetDefaultsdefined in thenx.jsonfile - Individual project level configuration files (
package.jsonandproject.json)
Each source will overwrite the previous source. That means targetDefaults will overwrite inferred tasks and project level configuration will overwrite both targetDefaults and inferred tasks. The combined project configuration can be viewed in the project details view by using Nx Console in your IDE or by running:
nx show project myproject --webdemo
Root: packages/demo
Type:application
Targets
build
vite build
dev
vite dev
The project details view also shows where each setting is defined so that you know where to change it. From the terminal, nx show target prints one resolved target, and --verbose adds the file or plugin behind each value:
nx show target myproject:build --verboseNx configuration sits next to the configuration of the tools each project uses, at both the workspace and the project level:
| Scope | Nx configuration | Tool configuration (TypeScript example) |
|---|---|---|
| Workspace | /nx.json | /tsconfig.base.json |
| Project | /packages/myproject/package.json | /packages/myproject/tsconfig.json |
Tool configuration stays the source of truth for the tool itself, and plugins read it to create the inferred tasks.
Project level configuration files
Section titled “Project level configuration files”If you need to edit your project settings or modify an inferred task, you can do so in either package.json or project.json files. The examples on this page show both styles. Nx merges the two files to get each project's configuration. The full machine readable schema is available on GitHub.
When to Use package.json vs project.json
Section titled “When to Use package.json vs project.json”Both package.json and project.json can be used to configure Nx targets, and both support the same configuration options including executors:
- package.json: Use the
"nx"property to define targets with executors, options, and other Nx-specific configuration - project.json: A dedicated Nx configuration file that keeps your
package.jsonfocused on package metadata
The choice between package.json and project.json is primarily a matter of preference. The package.json is standard for JavaScript projects, so you may prefer to use that over the Nx-specific project.json file.
The following configuration creates build and test targets for Nx.
{ "name": "mylib", "scripts": { "test": "jest", }, "nx": { // you could also do this in "scripts", but this "targets" configuration also supports Nx executors "targets": { "build": { "command": "tsc -p tsconfig.lib.json", }, }, },}{ "root": "libs/mylib/", "targets": { "test": { "command": "jest", "options": {/* ... */}, }, "build": { "executor": "@nx/js:tsc", "options": {/* ... */}, }, },}You can invoke nx build mylib or nx test mylib without any extra configuration.
Below are some more complete examples of project configuration files. For a more intuitive understanding of the roles of each option, you can highlight the options in the excerpt below that relate to different categories. Orchestration settings control the way Nx runs tasks. Execution settings control the actual task that is run. Caching settings control when Nx caches a task and what is actually cached.
{ "name": "mylib", "scripts": { "test": "jest", "build": "tsc -p tsconfig.lib.json", // the actual command here is arbitrary "ignored": "exit 1", }, "nx": { "namedInputs": { "default": ["{projectRoot}/**/*"], "production": ["!{projectRoot}/**/*.spec.tsx"], }, "targets": { "build": { "inputs": ["production", "^production"], "outputs": ["{workspaceRoot}/dist/libs/mylib"], "dependsOn": ["^build"], }, "test": { "inputs": ["default", "^production"], "outputs": [], "dependsOn": ["build"], }, }, "includedScripts": ["test", "build"], // If you want to limit the scripts Nx sees, you can specify a list here. },}{ "root": "libs/mylib/", "sourceRoot": "libs/mylib/src", "projectType": "library", "tags": ["scope:myteam"], "implicitDependencies": ["anotherlib"], "namedInputs": { "default": ["{projectRoot}/**/*"], "production": ["!{projectRoot}/**/*.spec.tsx"] }, "targets": { "test": { "inputs": ["default", "^production"], "outputs": [], "dependsOn": ["build"], "command": "jest", "options": {} }, "build": { "inputs": ["production", "^production"], "outputs": ["{workspaceRoot}/dist/libs/mylib"], "dependsOn": ["^build"], "executor": "@nx/js:tsc", "options": {} } }}Task definitions (Targets)
Section titled “Task definitions (Targets)”A large portion of project configuration is related to defining the tasks for the project. In addition, to defining what the task actually does, a task definition also has properties that define the way that Nx should run that task. Those properties are described in detail below.
Caching is configured by specifying "cache": true in a target's configuration. This will tell Nx that it's ok to cache the results of a given target. For instance, if you have a target that runs tests, you can specify "cache": true in the target default configuration for test and Nx will cache the results of running tests.
{ "targets": { "test": { "cache": true } }}Parallelism
Section titled “Parallelism”In Nx 19.5.0+, tasks can be configured to support parallelism or not. By default, tasks are run in parallel with other tasks on a given machine. However, in some cases, tasks can require a shared resource such as a port or memory. For these cases, setting "parallelism": false, will ensure that those tasks will not run in parallel with other tasks on a single machine. For example, if the e2e tasks all require port 4200, running them in parallel will conflict so the targets can specify to not support parallelism:
{ "targets": { "e2e": { "parallelism": false } }}Inputs and named inputs
Section titled “Inputs and named inputs”Each cacheable task needs to define inputs which determine whether the task outputs can be retrieved from the cache or the task needs to be re-run. The namedInputs defined in nx.json or project level configuration are sets of reusable input definitions.
A typical set of inputs may look like this:
{ "namedInputs": { "default": ["{projectRoot}/**/*"], // every file in the project "production": ["default", "!{projectRoot}/**/*.spec.tsx"], // except test files }, "targets": { "build": { "inputs": [ "production", // this project's production files { "externalDependencies": ["vite"] }, // the version of the vite package ], }, },}Outputs
Section titled “Outputs”Targets may define outputs to tell Nx where the target is going to create file artifacts that Nx should cache. "outputs": ["{workspaceRoot}/dist/libs/mylib"] tells Nx where the build target is going to create file artifacts.
This configuration is usually not needed. Nx comes with reasonable defaults (imported in nx.json) which implement the configuration above.
Specifically, by default, the following locations are cached for builds:
{workspaceRoot}/dist/{projectRoot},{projectRoot}/build,{projectRoot}/dist,{projectRoot}/public
Read the configure outputs for task caching recipe for helpful tips for setting outputs.
Basic example
Section titled “Basic example”Usually, a target writes to a specific directory or a file. The following instructs Nx to cache dist/libs/mylib and build/libs/mylib/main.js:
{ "targets": { "build": { "outputs": [ "{workspaceRoot}/dist/libs/mylib", "{workspaceRoot}/build/libs/mylib/main.js" ] } }}Specifying globs
Section titled “Specifying globs”Sometimes, multiple targets might write to the same directory. When possible it is recommended to direct these targets into separate directories.
{ "targets": { "build-js": { "outputs": ["{workspaceRoot}/dist/libs/mylib/js"] }, "build-css": { "outputs": ["{workspaceRoot}/dist/libs/mylib/css"] } }}But if the above is not possible, globs (parsed by the GlobSet Rust library) can be specified as outputs to only cache a set of files rather than the whole directory.
{ "targets": { "build-js": { "outputs": ["{workspaceRoot}/dist/libs/mylib/**/*.{js,map}"] }, "build-css": { "outputs": ["{workspaceRoot}/dist/libs/mylib/**/*.css"] } }}More advanced patterns can be used to exclude files and folders in a single line
{ "targets": { "build-js": { "outputs": ["{workspaceRoot}/dist/libs/!(cache|.next)/**/*.{js,map}"] }, "build-css": { "outputs": ["{workspaceRoot}/dist/libs/mylib/**/!(secondary).css"] } }}dependsOn
Section titled “dependsOn”Targets can depend on other targets. This is the relevant portion of the configuration file:
{ "targets": { "build": { "dependsOn": ["^build"] }, "test": { "dependsOn": ["build"] } }}A common scenario is having to build dependencies of a project first before building the project. This is what the "dependsOn": ["^build"] property of the build target configures. It tells Nx that before it can build mylib it needs to make sure that mylib's dependencies are built as well. This doesn't mean Nx is going to rerun those builds. If the right artifacts are already in the right place, Nx will do nothing. If they aren't in the right place, but they are available in the cache, Nx will retrieve them from the cache.
Another common scenario is for a target to depend on another target of the same project. For instance, "dependsOn": ["build"] of the test target tells Nx that before it can test mylib it needs to make sure that mylib is built, which will result in mylib's dependencies being built as well.
You can also express task dependencies with an object syntax:
{ "targets": { "test": { "dependsOn": [ { "target": "build", // target name "params": "ignore" // "forward" or "ignore", defaults to "ignore" } ] } }}{ "targets": { "build": { "dependsOn": [ { "dependencies": true, // Run this target on all dependencies first "target": "build", // target name "params": "ignore" // "forward" or "ignore", defaults to "ignore" } ] } }}{ "targets": { "build": { "dependsOn": [ { "projects": ["my-app"], // Run build on "my-app" first "target": "build", // target name "params": "ignore" // "forward" or "ignore", defaults to "ignore" } ] } }}Starting from v19.5.0, wildcards can be used to define dependencies in the dependsOn field.
{ "targets": { "test": { "dependsOn": [ { "target": "build", // target name "params": "ignore" // "forward" or "ignore", defaults to "ignore" }, "build-*", // support for using wildcards in dependsOn, matches: "build-css", "build-js" targets of current project "^build-*", // matches tasks: "build-css", "build-js" targets of dependencies "*build-*", // matches tasks: "build-css", "build-js" as well as "task-with-build-in-middle" targets of current project "^*build-*" // matches tasks: "build-css", "build-js" as well as "task-with-build-in-middle" targets of dependencies ] } }}Examples
Section titled “Examples”You can write the shorthand configuration above in the object syntax like this:
{ "targets": { "build": { "dependsOn": [{ "dependencies": true, "target": "build" }] // Run build on my dependencies first }, "test": { "dependsOn": [{ "target": "build" }] // Run build on myself first } }}With the expanded syntax, you also have a third option available to configure how to handle the params passed to the target. You can either forward them or you can ignore them (default).
{ "targets": { "build": { // forward params passed to this target to the dependency targets "dependsOn": [ { "projects": "{dependencies}", "target": "build", "params": "forward" } ] }, "test": { // ignore params passed to this target, won't be forwarded to the dependency targets "dependsOn": [ { "projects": "{dependencies}", "target": "build", "params": "ignore" } ] }, "lint": { // ignore params passed to this target, won't be forwarded to the dependency targets "dependsOn": [{ "projects": "{dependencies}", "target": "build" }] } }}This also works for a target of the same project. Leave out projects:
{ "targets": { "build": { // forward params passed to this target to the project target "dependsOn": [{ "target": "pre-build", "params": "forward" }] } }}The expanded syntax also accepts an options property, which controls whether the options configured on this target are forwarded to the dependency targets. Like params, it can be set to "forward" or "ignore" and defaults to "ignore".
{ "targets": { "build": { "options": { "out": "dist/mylib" }, // forward the options of this target to the dependency target "dependsOn": [{ "target": "pre-build", "options": "forward" }] } }}When the target runs with a configuration, the options of that configuration are merged over the target options before they are forwarded. params and options are set independently of each other, and when both are forwarded, the params passed on the command line take precedence over the forwarded options.
The expanded syntax also accepts "inputs": false, which keeps the inputs of a continuous dependency out of the target's hash. It has no effect on other dependencies.
Additionally, when using the expanded object syntax, you can specify individual projects in version 16 or greater.
{ "targets": { "build": { // Run is-even:pre-build and is-odd:pre-build before this target "dependsOn": [ { "projects": ["is-even", "is-odd"], "target": "pre-build" } ] } }}This configuration is usually not needed. Nx comes with reasonable defaults (imported in nx.json) which implement the configuration above.
Continuous
Section titled “Continuous”In Nx 21+, tasks that never exit (sometimes called long-running processes) can be configured with "continuous": true to prevent their dependent tasks from waiting for task completion. For example, the e2e task depends on a continuous serve task to ensure that the development server is running.
In this example, application's configuration labels the serve task as continuous.
{ "targets": { "serve": { "continuous": true } }}And the E2E project's e2e task has a dependency on the serve task, which ensures that the server is running when we run the e2e task.
{ "targets": { "e2e": { "dependsOn": [ { "projects": "myapp", "target": "serve" } ] } }}The e2e task also hashes the inputs of the serve task it depends on. Set "inputs": false on the dependsOn entry to hash only the e2e task's own inputs. See inputs of continuous dependencies.
Wait for a continuous task to be ready
Section titled “Wait for a continuous task to be ready”A dependent task starts as soon as its continuous dependency has started. That can be before the server accepts requests. To wait longer, describe in readyWhen how Nx detects that the continuous target is ready. Then set waitFor to ready on the dependsOn entry of each task that should wait.
{ "targets": { "serve": { "continuous": true, "readyWhen": { "url": "http://localhost:4200" } } }}{ "targets": { "e2e": { "dependsOn": [ { "projects": "myapp", "target": "serve", "waitFor": "ready" } ] } }}readyWhen is an object with exactly one of these keys:
url: ready when an HTTP or HTTPSGETrequest gets a status from 200 to 403. A redirect counts as ready and isn't followed. A 404 at the root path is retried at/index.html. Certificates are verified, except for a loopback address such as127.0.0.1, and forlocalhostor a*.localhostname whose every address is loopback, where a self-signed development certificate works. Proxy environment variables such asHTTP_PROXYandNO_PROXYapply to other hosts. A loopback request is never proxied. A0.0.0.0host connects to127.0.0.1, and[::]connects to[::1], so both count as loopback.port: ready when a TCP connection to the port succeeds. Nx tries both127.0.0.1and::1unlesshostnames the address to connect to. Ahostof0.0.0.0connects to127.0.0.1, and::connects to::1.local-ip,local-ipv4andlocal-ipv6resolve the way webpack-dev-server and the Rspack dev server resolve them. With aportof0orauto, the server picks its port when it starts. Nx then runs no check, and the target counts as ready once it has started.command: ready when the command, run through the shell at the workspace root, exits with code 0. The command gets the environment the task runs with, and the task's options as JSON in theNX_TASK_OPTIONSenvironment variable. Use it for a container health check:docker inspect --format='{{.State.Health.Status}}' db | grep -qx healthy.logMatches: ready when the task output has contained the string, or every string of an array. The order doesn't matter. Aprefixset on annx:run-commandscommand is part of the matched text. Color codes and other terminal control sequences are removed before matching.signal: ready when the task itself reports that it's ready. Set it totrue. See signal readiness from the task.
Strings in readyWhen can use the {workspaceRoot}, {projectRoot}, {projectName}, {options.*}, and {env.*} placeholders. {options.*} reads the options the executor receives: the target options, the configuration in use, the command-line overrides and the executor's defaults. So "url": "http://localhost:{options.port}" follows --port, and works without a port option when the executor has a default for it. port accepts such a string too, for example "{options.port}". {env.*} reads the environment the task runs with, including its .env files. For an nx:run-commands target, that includes its env and envFile options. The variable name can contain only the letters a to z in either case, digits, _, ., -, and parentheses. A placeholder can list fallbacks after ??, and Nx uses the first one that is set and not empty. In host and port, true and false count as not set. A flag passed without a value, such as --host, parses as true, and --no-host parses as false. In port, an empty option such as --port= counts as 0, so the fallbacks after it aren't used. The last fallback can be plain text, as in "{options.port ?? env.PORT ?? 4200}". A placeholder that resolves to no value makes readyWhen invalid, with an error that names the placeholder. Other text in braces, such as a {{.State.Health.Status}} template in a command, is left as it is. In port and host, such text makes readyWhen invalid instead.
The optional timeout key is how long Nx waits for readiness, in milliseconds. It defaults to 600000, 10 minutes, which covers a cold first build. To give an inferred check more time without replacing it, spread it: "readyWhen": { "...": true, "timeout": 1200000 }. nx show target shows a target's readyWhen, with the timeout Nx waits and where the check came from, and the project details in nx graph show the check and its source. The optional interval key is the time between attempts, in milliseconds. It defaults to 250. A signal check doesn't take interval.
If the target isn't ready within timeout, its task fails and the tasks waiting for it are skipped, as with any failed dependency. The continuous task keeps running until nothing in the run needs it. When no task in the run waits for the target, the failed check logs its reason only with NX_VERBOSE_LOGGING=true. An invalid readyWhen, such as a port above 65535, fails the task before it starts when a task in the run waits for it. Otherwise Nx prints a warning and runs the task without a check. Tasks whose dependsOn entry doesn't set waitFor to ready start as before. When one entry asks for ready and another entry reaches the same continuous target without it, the task waits for ready. A continuous target without readyWhen counts as ready once it has started. On such a dependency, waitFor: "ready" changes nothing. The WASM build of Nx can't run readiness checks, so a target with a check fails there when a task waits for it. A target with a port of 0 or auto runs no check, so it works there too. A signal check works there as well.
A readyWhen in targetDefaults replaces the whole readyWhen a plugin infers, and one in the project configuration replaces both. Set readyWhen to null to turn off a check inherited from a plugin or targetDefaults.
readyWhen is unrelated to the option of the same name on the nx:run-commands executor. That option marks the run-commands task itself as done.
Signal readiness from the task
Section titled “Signal readiness from the task”With "signal": true, Nx doesn't probe the task from outside. Instead, code running in the task reports that the task is ready, with the address it listens on. These report it once the server listens:
NxAppWebpackPlugin,NxAppRspackPlugin, and the standaloneNxReadySignalPluginfor webpack and Rspack.- The
NgRspackPluginthatcreateConfigfrom@nx/angular-rspackadds to Angular Rspack configs. - The
nxReadySignal()Vite plugin and thepluginNxReadySignal()Rsbuild plugin. - The
@nx/nuxt/ready-signalNuxt module, which reports only oncenuxt devhas built the app and stops answering 503. - The Metro reporter that the inferred React Native
starttask passes toreact-native start. - The
@nx/web:file-serverexecutor. - Any other executor or Angular builder that returns a successful result with a
baseUrl, such as@angular/build:dev-server. Nx reports thatbaseUrlfor it, with a0.0.0.0or[::]host replaced bylocalhost.
The report carries the port the server actually uses, so it's right however the port was chosen. Generators write "readyWhen": { "signal": true } on the @nx/web:file-server and Angular dev server targets they create. They also write it on the serve target of Express, Fastify, Koa, and NestJS apps, and on the Next.js serve-custom-server target. @nx/web and @nx/angular each ship an update-24-0-0-add-ready-when-signal migration. It adds the setting to existing targets that use those executors and builders. The file server runs its buildTarget before it listens. The @nx/web migration therefore also adds that target to the file server target's dependsOn.
{ "targets": { "serve": { "continuous": true, "readyWhen": { "signal": true } } }}A signal check only passes on the report, so use it for a target whose server runs one of those plugins or calls emitReadySignal itself. The webpack, Rspack, Vite, and Rsbuild plugins infer it only when the config loads one of those plugins, and a check that reads the config at task time otherwise. The Nuxt plugin infers it on the dev server task only when the config loads the Nuxt module. The @nx/web:file-server targets that the webpack, Rspack, Vite, Nuxt, and Storybook plugins infer, such as serve-static, always use it.
The plugins below infer a command check on their server targets instead. It runs when the task runs, with the task's environment and options, and waits for the server's port.
@nx/angular/plugin:angular.jsontargets that use a dev server or SSR dev server builder. The check reads the target fromangular.jsonand resolves the port the wayng servedoes.@nx/next/plugin: thenext devandnext starttargets.@nx/expo/plugin: theexpo starttargets, which wait for the Metro port.@nx/nuxt/plugin: thenuxt devtarget, when the Nuxt config doesn't load@nx/nuxt/ready-signal. The check finds the port and host the waynuxt devdoes. It then waits until the server answers with any status other than 503, whichnuxt devanswers until it serves the app.@nx/react/router-plugin: thereact-router-servetarget. Thereact-router devtarget gets the Vite check, if@nx/viteis installed at the workspace root.@nx/storybook/plugin: thestorybook devtarget. It waits only when a port is set, through--port,SBCONFIG_PORT, orPORT. Without one, Storybook picks a free port, and the target counts as ready once it has started.
@storybook/angular:start-storybook targets report no address. The Storybook plugin and the @nx/storybook:configuration generator give them a check with "port": "{env.SBCONFIG_PORT ?? options.port ?? 9009}" and "host": "{env.SBCONFIG_HOSTNAME ?? options.host ?? localhost}" instead. The update-24-0-0-add-start-storybook-ready-when migration of @nx/storybook adds that check to existing targets. It also sets continuous: true on those that leave continuous unset, unless they set smokeTest.
A task that waits for a signaling target gets the reported address in the NX_READY_URL environment variable, when exactly one of the targets it waits for reported one. That includes a target another Nx process started, such as a dev server already running in another terminal. To apply it to an address you'd otherwise hard-code, call getReadyUrl from @nx/devkit, for example getReadyUrl('http://localhost:4200/app'). It takes the protocol and port from NX_READY_URL and keeps the path and query. A localhost host stays as it is when the server listens on a loopback address, and any other host moves to the one the server reported. Without NX_READY_URL, it returns the address unchanged.
To report readiness from your own server, call emitReadySignal from @nx/js/ready-signal once it listens. Import it only when Nx waits for the server. The server then loads nothing from Nx otherwise, and keeps running where @nx/js, a dev dependency, isn't installed. The import goes through new Function so TypeScript and bundlers leave it as a runtime import:
const server = app.listen(port, async () => { if (process.env.NX_READY_SIGNAL_SOCKET) { try { // Function keeps TypeScript and bundlers from rewriting or bundling the import const load = new Function('s', 'return import(s)') as ( s: string ) => Promise<{ emitReadySignal(server: unknown): boolean }>; (await load('@nx/js/ready-signal')).emitReadySignal(server); } catch { // @nx/js isn't installed } }});Pass the server, and Nx reads the address it listens on, or pass the URL as a string. It does nothing outside a task whose readyWhen is signal. Code that already depends on @nx/devkit, such as an executor or a bundler plugin, can import emitReadySignal from @nx/devkit instead.
If you change an inferred dev target's command to something that doesn't report, set readyWhen on the target too, or the tasks waiting for it fail after the timeout.
Ultracache
Section titled “Ultracache”Nx Cloud records the files each task reads and writes. From the reads it builds each task's Ultracache configuration, which Nx hashes the task from in place of the target's declared inputs. Inputs with "always": true stay in the hash. Nx still caches the target's declared outputs. The ultracache property adjusts that for a single target.
Set mode to choose how a target participates:
| Mode | Records IO | Reports undeclared access | Applies the recording |
|---|---|---|---|
on | yes | no | yes |
warn | yes | warns | no |
error | yes | fails the CI run | no |
off | no | no | no |
The modes apply when your workspace has Ultracache turned on in Nx Cloud.
on is the default. Use warn on a target whose inputs depend on dynamic behavior or external state: Nx keeps watching it and tells you what it touched, but hashes it from what it declared. error also hashes from what the target declared, and fails the CI run when the target reads a file outside its inputs or writes one outside its outputs. Use off to stop recording it at all.
In a workspace with Ultracache turned on, nx show target and the project details in nx graph say which mode applies to a target.
{ "targets": { "build": { "ultracache": { "mode": "warn" } } }}Set collectStats: true to include successful stat metadata accesses in the recorded inputs. It defaults to false. Missing-path probes are tracked either way. Turning collectStats on or off re-runs the task, so its next recording follows the new setting.
{ "targets": { "build": { "ultracache": { "collectStats": true } } }}Use ignoreReads and ignoreWrites to keep recording the target while excluding paths from its report. The patterns are globs relative to the workspace root.
{ "targets": { "build": { "ultracache": { "ignoreReads": ["tmp/**"], "ignoreWrites": ["**/.cache/**"] } } }}When Nx hashes a task from its Ultracache configuration, an excluded read doesn't count toward its hash, even if the target declares the path with includeIgnored. An input with "always": true keeps its files in the hash either way. Changing ignoreReads re-runs the task, so its next recording follows the new patterns.
A target that defines ultracache replaces the inherited settings rather than adding to it. Use the spread token to merge instead, either at the object level to keep inherited keys, or inside ignoreReads and ignoreWrites to keep inherited patterns.
{ "targets": { "build": { "ultracache": { "...": true, "ignoreReads": ["...", "tmp/**"] } } }}A key written after the spread token overrides the inherited value. For example, "ultracache": { "...": true, "collectStats": false } keeps the other inherited settings and turns off successful stat collection, even if the inherited collectStats is true.
Sync generators
Section titled “Sync generators”In the same way that dependsOn tells Nx to run another task before running this task, the syncGenerator property tells Nx to run a generator to ensure that your files are in the correct state before this task is run. Sync generators are especially useful for keeping configuration files up to date with the project graph.
{ "targets": { "build": { "syncGenerators": ["some-plugin:my-sync-generator"] } }}Executor/command options
Section titled “Executor/command options”To define what a task does, you must configure which command or executor will run when the task is executed. In the case of inferred tasks you can provide project-specific overrides. As an example, if your repo has projects with a build inferred target running the vite build command, you can provide some extra options as follows:
{ "targets": { "build": { "options": { "assetsInlineLimit": 2048, "assetsDir": "static/assets" } } }}For more details on how to pass args to the underlying command see the Pass Args to Commands recipe.
In the case of an explicit target using an executor, you can specify the executor and the options specific to that executor as follows:
{ "targets": { "build": { "executor": "@nx/js:tsc", "options": { "generateExportsField": true } } }}Spread token
Section titled “Spread token”By default, each configuration source overwrites the previous one for every property it defines. The spread token ("...") lets you control merge priority rather than always replacing.
In arrays, "..." is substituted with the items from the base array at that position:
{ "targets": { "build": { "inputs": ["my-project-input", "..."] } }}If the inferred target has inputs: ["default", "^production"], the result is ["my-project-input", "default", "^production"].
In objects, a key of "..." set to true spreads base properties at that position. Keys defined after "..." override base values; keys defined before "..." can be overridden by base values.
{ "targets": { "build": { "options": { "env": { "MY_VAR": "my-value", "...": true } } } }}Nx processes target configuration down to options[x], configurations[x][y], and the keys of ultracache; values below that are opaque to the merge pipeline. Spread is therefore resolved at these levels:
| Level | Example |
|---|---|
| Target root | "build": { "dependsOn": ["lint"], "...": true } |
inputs, outputs, dependsOn, syncGenerators | "inputs": ["my-input", "..."] |
options | "options": { "...": true, "outputPath": "dist/custom" } |
options[x] | "options": { "env": { "MY_VAR": "val", "...": true } } |
configurations | "configurations": { "my-config": { ... }, "...": true } |
configurations[x] | "configurations": { "prod": { "...": true, "sourceMap": false } } |
configurations[x][y] | "configurations": { "prod": { "env": { "MY_VAR": "val", "...": true } } } |
ultracache | "ultracache": { "...": true, "mode": "off" } |
ultracache.ignoreReads, ultracache.ignoreWrites | "ultracache": { "ignoreReads": ["...", "tmp/**"] } |
Target metadata
Section titled “Target metadata”You can add additional metadata to be attached to a target. For example, you can provide a description stating what the target does:
{ "targets": { "build": { "metadata": { "description": "Build the application for production", }, }, },}Project metadata
Section titled “Project metadata”The following properties describe the project as a whole.
You can annotate your projects with tags as follows:
{ "name": "mylib", "nx": { "tags": ["scope:myteam"], },}{ "root": "libs/mylib", "tags": ["scope:myteam"],}You can configure lint rules using these tags to, for instance, ensure that libraries belonging to myteam are not depended on by libraries belong to theirteam.
implicitDependencies
Section titled “implicitDependencies”Nx uses powerful source-code analysis to figure out your workspace's project graph. Some dependencies cannot be deduced statically, so you can set them manually like this. The implicitDependencies property is parsed with the minimatch library, so you can review that syntax for more advanced use cases.
{ "name": "mylib", "nx": { "implicitDependencies": ["anotherlib"], },}{ "root": "libs/mylib", "implicitDependencies": ["anotherlib"],}You can also remove a dependency as follows:
{ "name": "mylib", "nx": { "implicitDependencies": ["!anotherlib"] # regardless of what Nx thinks, "mylib" doesn't depend on "anotherlib" }}{ "root": "libs/mylib", "implicitDependencies": ["!anotherlib"] # regardless of what Nx thinks, "mylib" doesn't depend on "anotherlib"}An implicit dependency could also be a glob pattern:
{ "name": "mylib", "nx": { "implicitDependencies": ["shop-*"] # "mylib" depends on all projects beginning with "shop-" }}{ "root": "libs/mylib", "implicitDependencies": ["shop-*"] # "mylib" depends on all projects beginning with "shop-"}Release
Section titled “Release”The release property allows project-level overrides for the nx release command. This is particularly useful for configuring Docker image publishing.
Docker configuration experimental
Section titled “Docker configuration experimental”Projects with Docker images can override the global Docker configuration:
{ "name": "api", "release": { "docker": { // Override the repository name for this specific project "repositoryName": "acme/api", }, },}The repositoryName specified here will override any global or group-level Docker repository configuration when publishing this project's Docker image.
Metadata
Section titled “Metadata”You can add additional metadata to be attached to the project. For example, you can provide a description for your project:
{ "name": "admin", "metadata": { "description": "This is the admin application", },}Including package.json files as projects in the graph
Section titled “Including package.json files as projects in the graph”Any package.json file that is referenced by the workspaces property in the root package.json file will be included as a project in the graph. If you are using Lerna, projects defined in lerna.json will be included. If you are using pnpm, projects defined in pnpm-workspace.yml will be included.
If you want to ignore a particular package.json file, exclude it from those tools. For example, you can add !packages/myproject to the workspaces property.
Ignoring package.json scripts
Section titled “Ignoring package.json scripts”Nx merges package.json scripts with any targets defined in project.json. If you only wish for some scripts to be used as Nx targets, you can specify them in the includedScripts property of the project's package.json.
{ "name": "my-library", "version": "0.0.1", "scripts": { "build": "tsc", "postinstall": "node ./tasks/postinstall" }, "nx": { "includedScripts": ["build"] }}