Skip to content

Migrate from @nx-dotnet/core to @nx/dotnet

This guide provides a streamlined migration path from the community @nx-dotnet/core plugin to Nx's official @nx/dotnet plugin.

The official @nx/dotnet plugin represents a natural evolution, building on lessons learned from the community plugin while embracing native .NET workflows:

  • Project inference: Automatic detection of .NET projects without configuration with Nx inferred targets
  • MSBuild integration: Direct use of Microsoft's APIs for accurate dependency analysis
  • Native CLI first: Uses dotnet commands directly instead of custom wrappers
  • Minimal abstraction: Simpler implementation with fewer dependencies

This results in a faster, and more reliable .NET plugin.

Before starting the migration:

  • [ ] Upgrade to .NET SDK 8.0 or later (required)
  • [ ] Locate your current @nx-dotnet/core configuration (see below)
  • [ ] Review any custom generators and executors you're using
  • [ ] Ensure your projects build successfully with current setup

The @nx-dotnet/core plugin configuration can be in one of two places:

{
"plugins": [
{
"plugin": "@nx-dotnet/core",
"options": {
"inferredTargets": { ... },
"solutionFile": "...",
// ... other options
}
}
]
}
Terminal window
nx add @nx/dotnet

This automatically:

  • Adds @nx/dotnet as a dependency
  • Registers the plugin in nx.json
  • Configures target inputs
  • Updates .gitignore
Terminal window
npm uninstall @nx-dotnet/core @nx-dotnet/utils @nx-dotnet/dotnet

Clean up the relevant workspace configurations:

  • Remove @nx-dotnet/core from the plugins array in nx.json (if present)
  • Delete .nx-dotnet.rc.json (if it exists)

Move any customized target configurations from your @nx-dotnet/core config to the new @nx/dotnet plugin options.

Before (in nx.json or .nx-dotnet.rc.json):

{
"inferredTargets": {
"build": "build",
"test": {
"targetName": "test:dotnet",
"cache": false
}
}
}

After (in nx.json):

nx.json
{
"plugins": [
{
"plugin": "@nx/dotnet",
"options": {
"build": {
"targetName": "build"
},
"test": {
"targetName": "test:dotnet"
}
}
}
]
}
Terminal window
nx reset
nx graph

The nx graph command should show all your .NET projects with their dependencies correctly detected. If you encounter any issues, see the Troubleshooting section below.

Here's what changes in your day-to-day usage with the new @nx/dotnet plugin:

TaskOld (@nx-dotnet/core)New (@nx/dotnet)
Create applicationnx g @nx-dotnet/core:app my-apidotnet new webapi -n MyApi
Create librarynx g @nx-dotnet/core:lib my-libdotnet new classlib -n MyLib
Add project referencenx g @nx-dotnet/core:project-reference --source A --target Bdotnet add reference ../B/B.csproj
Add NuGet packagenx g @nx-dotnet/core:nuget-referencedotnet add package PackageName
Build projectnx build my-apinx build my-api ✅ (same)
Run testsnx test my-apinx test my-api ✅ (same)
Serve/watchnx serve my-apidotnet watch run (or configure custom target)

The plugin automatically creates these targets for .NET projects:

TargetWhen CreatedCommand
buildAll projectsdotnet build --no-restore --no-dependencies
testTest projects onlydotnet test --no-build --no-restore
restoreAll projectsdotnet restore
cleanAll projectsdotnet clean
publishExecutable projectsdotnet publish
packLibrary projectsdotnet pack

The serve and format targets are not automatically created. serve defaults to a target named watch now. To run it, you'd need to run nx run my-api:watch run. To configure the watch target to act like serve, you could set the following in nx.json:

nx.json
{
"plugins": [
{
"plugin": "@nx/dotnet",
"options": {
"watch": {
"targetName": "serve",
"args": ["run"]
}
}
}
]
}

The format target is not present by default. You should add it as a custom target if desired.

Migrating from Explicit Executor Configurations

Section titled “Migrating from Explicit Executor Configurations”

If you have project.json files that explicitly configure @nx-dotnet/core executors, you'll need to update them to use command targets.

Before (project.json):

project.json
{
"name": "my-api",
"targets": {
"build": {
"executor": "@nx-dotnet/core:build",
"options": {
"configuration": "Release",
"noDependencies": true
}
},
"test": {
"executor": "@nx-dotnet/core:test",
"options": {
"testProject": "MyApi.Tests.csproj"
}
},
"serve": {
"executor": "@nx-dotnet/core:serve",
"options": {
"project": "MyApi.csproj"
}
}
}
}

After (project.json):

project.json
{
"name": "my-api",
"targets": {
"build": {
"command": "dotnet build",
"options": {
"cwd": "{projectRoot}",
"args": ["--configuration", "Release", "--no-dependencies"]
}
},
"test": {
"command": "dotnet test MyApi.Tests.csproj",
"options": {
"cwd": "{projectRoot}"
}
},
"serve": {
"command": "dotnet watch run",
"options": {
"cwd": "{projectRoot}"
}
}
}
}

If you previously set inferProjects: false in your @nx-dotnet/core config, this option no longer exists in @nx/dotnet. The new plugin always infers projects automatically.

Why this changed:

  • Project inference is a core feature of how Nx plugins work
  • Manual project management doesn't align with Nx's preferred automatic detection model
  • Maintaining explicit project configurations is error-prone

Migration path:

  1. If you disabled inference to exclude certain projects:

    • Use the exclude property in the plugin configuration:
      nx.json
      {
      "plugins": [
      {
      "plugin": "@nx/dotnet",
      "exclude": ["legacy-projects/**", "temp-projects/**"]
      }
      ]
      }
  2. If you disabled inference to use explicit project.json files:

    • The new plugin will still detect your projects via .csproj files
    • You can keep project.json files to customize targets, but they're optional
    • Consider removing them to use the automatically inferred targets

If you used moduleBoundaries in your @nx-dotnet/core config, you may want to migrate to Nx Conformance rules

The script used to evaluate module boundaries is missing several features from the eslint and conformance implementations, and is not present in the new plugin. If you wish to continue using it, you'll need to inline the implementation in your repository and update the path in Directory.build.targets. Otherwise, you should remove the target from Directory.build.targets.

Replace the sync generator with MSBuild's Central Package Management.

Create Directory.Packages.props at workspace root:

// Directory.Packages.props
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.0" />
</ItemGroup>
</Project>

Update project files to remove version attributes:

<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Newtonsoft.Json" />

Run these commands to verify everything works:

Terminal window
# Clear cache
nx reset
# Verify project detection
nx show projects
# Test builds
nx run-many -t build
# Test affected builds
nx affected -t build
# Run tests
nx run-many -t test

Symptom: Some .NET projects don't appear in nx show projects

Solution:

  • Ensure project files have .csproj, .fsproj, or .vbproj extensions
  • Check that the plugin is registered in nx.json
  • Run nx reset to clear the cache

Symptom: Build fails with "Could not find project reference"

Solution:

  • Verify the referenced project exists in the workspace
  • Ensure build targets have "dependsOn": ["^build"] (plugin adds this automatically)
  • Check that project references in .csproj files use correct relative paths
  • Run nx reset to clear stale cache

Symptom: Expected targets like test or pack don't show up

Solution:

  • test: Only created for projects with IsTestProject property or Microsoft.NET.Test.Sdk package
  • pack: Only created for library projects (not executables)
  • publish: Only created for executable projects (OutputType="Exe")
  • Use nx show project my-project to see all available targets

Symptom: Project names don't match expectations

Solution: Add a Name property to your .csproj file under the Nx property group:

<PropertyGroup>
<Nx>
<Name>my-custom-name</Name>
</Nx>
</PropertyGroup>

After completing the migration:

  • Review the incremental builds guide to understand how --no-dependencies optimizes builds
  • Configure Nx Cloud for improved repo experience for your team and CI
  • Set up custom targets for serve, lint, or other specialized tasks as needed
  • Update CI/CD pipelines to ensure .NET SDK 8.0+ is installed