Skip to content

Incremental Builds for .NET Projects

The @nx/dotnet plugin automatically configures projects to use the --no-dependencies flag when executing .NET build commands. This optimization allows Nx to manage build orchestration through its task graph, preventing duplicate compilations and maximizing cache efficiency.

When building outside of Nx, the .NET CLI typically handles dependency resolution and builds all project references automatically. However, this approach conflicts with Nx's task orchestration and caching mechanisms. By using --no-dependencies, the plugin delegates dependency management to Nx, which has full visibility into the project graph and can optimize build execution.

All .NET build targets generated by the plugin include a dependsOn configuration that ensures dependencies are built in the correct order:

{
"targets": {
"build": {
"command": "dotnet build",
"dependsOn": ["restore", "^build"]
}
}
}

The ^build dependency tells Nx to build all upstream dependencies before building the current project. This replaces the .NET CLI's built-in dependency resolution with Nx's more sophisticated task orchestration.

Consider a workspace with the following structure:

  • apps/WebApi
  • libs/ClassLib

If WebApi depends on ClassLib, running commands without --no-dependencies would result in:

nx build WebApi
  1. Nx analyzes the dependency graph and schedules nx build ClassLib
  2. Nx executes dotnet build libs/ClassLib/ClassLib.csproj
    • .NET CLI builds ClassLib
  3. Nx executes dotnet build apps/WebApi/WebApi.csproj
    • .NET CLI detects the ClassLib project reference
    • .NET CLI builds ClassLib again (duplicate build)
    • .NET CLI builds WebApi
nx affected -t build
  1. Nx determines both WebApi and ClassLib need to be built
  2. Nx runs nx build ClassLib first (due to dependency graph)
    • .NET CLI builds ClassLib
  3. Nx runs nx build WebApi
    • .NET CLI builds ClassLib again (duplicate build)
    • .NET CLI builds WebApi

This means ClassLib is compiled twice during affected builds, and the duplication scales with the number of project references.

The @nx/dotnet plugin automatically adds --no-dependencies to build commands, eliminating duplicate builds:

nx build WebApi
  1. Nx analyzes the dependency graph and schedules nx build ClassLib
  2. Nx executes dotnet build libs/ClassLib/ClassLib.csproj --no-dependencies
    • .NET CLI builds ClassLib
  3. Nx executes dotnet build apps/WebApi/WebApi.csproj --no-dependencies
    • .NET CLI builds only WebApi (skips ClassLib)
nx affected -t build
  1. Nx determines both WebApi and ClassLib need to be built
  2. Nx runs nx build ClassLib first
    • .NET CLI builds ClassLib
  3. Nx runs nx build WebApi
    • .NET CLI builds only WebApi (no duplicate compilation)

The benefits extend beyond avoiding duplicate builds—--no-dependencies also maximizes cache effectiveness.

Consider a scenario where you modify only WebApi, leaving ClassLib unchanged:

nx affected -t build
  1. Nx determines only WebApi needs rebuilding
  2. Since ClassLib hasn't changed, Nx restores it from cache
  3. Nx runs nx build WebApi
    • .NET CLI detects the ClassLib project reference
    • .NET CLI rebuilds ClassLib from source (ignoring the cache)
    • .NET CLI builds WebApi

The cached ClassLib output is effectively wasted because the .NET CLI rebuilds it anyway.

nx affected -t build
  1. Nx determines only WebApi needs rebuilding
  2. Since ClassLib hasn't changed, Nx restores it from cache
  3. Nx runs nx build WebApi --no-dependencies
    • .NET CLI builds only WebApi, using the cached ClassLib output

The cache is fully utilized, dramatically improving build performance in incremental scenarios.

The plugin automatically configures all .NET projects with appropriate target dependencies. For example, a typical library project configuration looks like:

{
"name": "ClassLib",
"targets": {
"build": {
"command": "dotnet build",
"options": {
"cwd": "{projectRoot}",
"args": ["--no-restore", "--no-dependencies"]
},
"dependsOn": ["^build"],
"cache": true,
"inputs": ["default", "^production"],
"outputs": ["{projectRoot}/bin", "{projectRoot}/obj"]
},
"restore": {
"command": "dotnet restore",
"options": {
"cwd": "{projectRoot}",
"args": ["--no-dependencies"]
},
"dependsOn": ["^restore"],
"cache": true
}
}
}
  • --no-dependencies: Prevents .NET from building project references
  • dependsOn: ["^build"]: Ensures dependencies are built first through Nx
  • cache: true: Enables Nx computation caching for the target
nx build my-project

Builds the specified project and all its dependencies in the correct order.

nx affected -t build

Builds only projects affected by recent changes, along with their dependencies.

nx run-many -t build --parallel=3

Builds multiple projects in parallel when possible, respecting dependency constraints.

The plugin automatically configures --no-dependencies for all targets. Avoid overriding this unless you have a specific reason.

Ensure all build targets include "dependsOn": ["^build"] so Nx knows to build dependencies first. The plugin handles this automatically during project detection.

Enable Nx Cloud to share build cache across your team and CI/CD pipelines, maximizing the performance benefits of incremental builds.

Use the Nx graph visualization to understand your project dependencies:

nx graph

This helps identify opportunities to further optimize your build graph.

Build errors referencing missing dependencies

Section titled “Build errors referencing missing dependencies”

If you see errors like "Could not find project reference", ensure:

  1. The referenced project exists in the workspace
  2. The dependsOn: ["^build"] configuration is present
  3. Run nx reset to clear the cache if stale