Skip to content

Nx brings smart task execution and caching to your .NET monorepo. .NET is a free, cross-platform, open-source developer platform for building many different types of applications. With .NET, you can use multiple languages, editors, and libraries to build for web, mobile, desktop, games, IoT, and more.

The Nx plugin for .NET registers .NET projects in your Nx workspace. It allows MSBuild tasks to be run through Nx. Nx effortlessly makes your CI faster.

Nx adds the following features to your workspace:

You can install Nx globally. Depending on your package manager, use one of the following commands:

Terminal window
npm add --global nx@latest

In any .NET workspace, run the following command to add Nx and the @nx/dotnet plugin:

Terminal window
nx init

Then, you can run .NET tasks using Nx. For example:

Terminal window
nx build <your dotnet project>

If you already have an Nx workspace set up, you can add the @nx/dotnet plugin by running the following command:

Terminal window
nx add @nx/dotnet

New projects can be created with the dotnet new CLI command, or any other method you may be familiar with. For example:

Terminal window
dotnet new webapi -o ./apps/my-api

Full project creation docs can be found here on the official Microsoft documentation.

The @nx/dotnet plugin uses MSBuild to analyze your .NET solution and project structure. When using nx add, the plugin is automatically configured in your nx.json file.

The plugin automatically detects .NET projects by scanning for the following project file patterns:

  • **/*.csproj (C# projects)
  • **/*.fsproj (F# projects)
  • **/*.vbproj (Visual Basic projects)

The plugin analyzes your MSBuild project files to determine:

  • Project dependencies (via <ProjectReference> elements)
  • Available build targets (build, test, clean, etc.)
  • Project outputs and configuration

Every cacheable target hashes the project's own files, the outputs of the projects it depends on, and the files MSBuild read from outside the project directory while evaluating it:

  • The nearest Directory.Build.props, Directory.Build.targets, Directory.Build.rsp, Directory.Solution.props, Directory.Solution.targets, Directory.Packages.props, and global.json above the project.
  • Every nuget.config and .editorconfig between the project and the workspace root, since NuGet and the analyzers read all of them.
  • Any other file the project imports, plus any Compile, AdditionalFiles, EmbeddedResource, or Content item linked in from another directory.
  • The NUGET_PACKAGES environment variable, because the restore output records the packages folder by absolute path.

Editing any of these files updates the project graph without an nx reset.

restore isn't cached and isn't part of the task chain. Run it once before build. The files it writes to the top level of obj are excluded from the outputs of build, publish, and pack, so a cache hit doesn't replace your restore.

A project gets a test target, and loses its pack target, when either MSBuild property is true:

  • IsTestProject, which Microsoft.NET.Test.Sdk sets.
  • IsTestingPlatformApplication, which Microsoft.Testing.Platform sets. The xunit.v3 and TUnit runners set this one, and may leave IsTestProject unset.

These are the two properties the .NET SDK itself checks before it will run a project. Nx therefore agrees with dotnet test about what a test project is. Referencing a framework such as xunit or NUnit is not enough on its own, which is what lets a library expose test helpers and keep its pack target. publish and run depend only on OutputType, so a runner built as an executable keeps both.

Both properties arrive with a restored package, so neither has a value before the project has been restored. Until then Nx falls back to a Microsoft.NET.Test.Sdk or Microsoft.Testing.* package reference, which it reads straight from the project file. Restore writes its imports under obj, which Nx doesn't watch, so run nx reset once afterwards to pick the properties up.

Set IsTestProject yourself to settle it and skip all of the above. IsTestingPlatformApplication is not read this way, because it describes the runner rather than the project, and MSTest.Sdk sets it to false on a project it has already marked as a test:

<PropertyGroup>
<IsTestProject>false</IsTestProject>
</PropertyGroup>

dotnet test writes nothing to disk on its own. Results appear only when a file logger or a coverage collector is configured, and they land in TestResults inside the project directory unless you say otherwise. To send them somewhere else and let Nx cache them, pass results-directory through target options together with the logger. The test target declares {projectRoot}/{options.results-directory} as an output. The value is relative to the project directory, the same way dotnet test reads the flag:

nx.json
{
"targetDefaults": {
"test": [
{
"filter": { "plugin": "@nx/dotnet" },
"options": {
"args": ["...", "--logger", "trx"],
"results-directory": "../../dist/test-reports/{projectRoot}"
}
}
]
}
}

To view inferred tasks for a project, open the project details view in Nx Console or run nx show project my-project in the command line.

The @nx/dotnet is configured in the plugins array in nx.json.

Each target type can be configured with:

  • targetName - Rename the target if needed (e.g., change "build" to "compile")
  • Additional target configuration properties (options, configurations, dependsOn, cache, inputs, outputs)
  • Set to false to disable a target

For example:

nx.json
{
"plugins": [
{
"plugin": "@nx/dotnet",
"options": {
"build": {
"targetName": "compile",
"configurations": {
"production": {
"optimization": true
}
}
},
"test": {
"targetName": "unit-test",
"dependsOn": ["build"]
},
"pack": false
}
}
]
}

Once a .NET project file has been identified, the targets are created with the configuration you specify in the nx.json plugins array. The default names for the inferred targets are:

  • build - Compiles the project
  • test - Runs unit tests (for test projects)
  • clean - Removes build outputs
  • restore - Restores NuGet package dependencies
  • publish - Publishes the application (for executable projects)
  • pack - Creates a NuGet package (for library projects)
  • watch - Watches the project for changes and rebuilds (automatically marked as continuous)
  • run - Runs the application (for executable projects)

Use include and exclude glob patterns on the plugin entry to scope inference. A target defaults plugin filter must use the exact identifier @nx/dotnet.

Not all targets are available for every project type. The plugin intelligently determines which targets to create based on the project type:

  • Console Applications & Web Projects: build, clean, restore, publish, watch, run
  • Class Libraries: build, clean, restore, pack, watch
  • Test Projects: build, clean, restore, test, watch

The @nx/dotnet plugin automatically marks the watch target as continuous, ensuring Nx handles it correctly during development. Unlike watch, run is not automatically marked as continuous as it may exit depending on the type of application. To mark run as continuous, you can configure it manually in project.json or nx.json.

In the nx.json, you can specify that run should be continuous like so:

nx.json
{
"plugins": [
{
"plugin": "@nx/dotnet",
"options": {
"run": {
"continuous": true
}
}
}
]
}

The @nx/dotnet plugin supports MSBuild configurations (Debug, Release, etc.) through Nx configuration system. You can run tasks with specific configurations:

Terminal window
# Build with Release configuration
nx build my-app --configuration release
# Build with Debug configuration (usually the default)
nx build my-app --configuration debug

In CI, Nx runs nx affected to rebuild and retest only the projects a change touches, and caches results to skip repeated work.

For a complete pipeline, see Set up CI.