This guide provides a streamlined migration path from the community @nx-dotnet/core plugin to Nx's official @nx/dotnet plugin.
Why Migrate?
Section titled “Why Migrate?”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
dotnetcommands directly instead of custom wrappers - Minimal abstraction: Simpler implementation with fewer dependencies
This results in a faster, and more reliable .NET plugin.
Prerequisites
Section titled “Prerequisites”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
Locating Your Configuration
Section titled “Locating Your Configuration”The @nx-dotnet/core plugin configuration can be in one of two places:
{ "plugins": [ { "plugin": "@nx-dotnet/core", "options": { "inferredTargets": { ... }, "solutionFile": "...", // ... other options } } ]}{ "inferredTargets": { ... }, "solutionFile": "...", // ... other options}Migration Steps
Section titled “Migration Steps”1. Install @nx/dotnet
Section titled “1. Install @nx/dotnet”nx add @nx/dotnetThis automatically:
- Adds
@nx/dotnetas a dependency - Registers the plugin in
nx.json - Configures target inputs
- Updates
.gitignore
2. Remove @nx-dotnet/core
Section titled “2. Remove @nx-dotnet/core”npm uninstall @nx-dotnet/core @nx-dotnet/utils @nx-dotnet/dotnetClean up the relevant workspace configurations:
- Remove
@nx-dotnet/corefrom thepluginsarray innx.json(if present) - Delete
.nx-dotnet.rc.json(if it exists)
3. Migrate Plugin Configuration
Section titled “3. Migrate Plugin Configuration”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):
{ "plugins": [ { "plugin": "@nx/dotnet", "options": { "build": { "targetName": "build" }, "test": { "targetName": "test:dotnet" } } } ]}4. Clear Cache and Verify
Section titled “4. Clear Cache and Verify”nx resetnx graphThe nx graph command should show all your .NET projects with their dependencies correctly detected. If you encounter any issues, see the Troubleshooting section below.
Key Workflow Changes
Section titled “Key Workflow Changes”Here's what changes in your day-to-day usage with the new @nx/dotnet plugin:
| Task | Old (@nx-dotnet/core) | New (@nx/dotnet) |
|---|---|---|
| Create application | nx g @nx-dotnet/core:app my-api | dotnet new webapi -n MyApi |
| Create library | nx g @nx-dotnet/core:lib my-lib | dotnet new classlib -n MyLib |
| Add project reference | nx g @nx-dotnet/core:project-reference --source A --target B | dotnet add reference ../B/B.csproj |
| Add NuGet package | nx g @nx-dotnet/core:nuget-reference | dotnet add package PackageName |
| Build project | nx build my-api | nx build my-api ✅ (same) |
| Run tests | nx test my-api | nx test my-api ✅ (same) |
| Serve/watch | nx serve my-api | dotnet watch run (or configure custom target) |
Default Targets Generated
Section titled “Default Targets Generated”The plugin automatically creates these targets for .NET projects:
| Target | When Created | Command |
|---|---|---|
build | All projects | dotnet build --no-restore --no-dependencies |
test | Test projects only | dotnet test --no-build --no-restore |
restore | All projects | dotnet restore |
clean | All projects | dotnet clean |
publish | Executable projects | dotnet publish |
pack | Library projects | dotnet pack |
Adding Back Missing Targets
Section titled “Adding Back Missing Targets”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:
{ "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.
Advanced Migration Scenarios
Section titled “Advanced Migration Scenarios”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):
{ "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):
{ "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}" } } }}Migrating from inferProjects: false
Section titled “Migrating from inferProjects: false”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:
If you disabled inference to exclude certain projects:
- Use the
excludeproperty in the plugin configuration:nx.json {"plugins": [{"plugin": "@nx/dotnet","exclude": ["legacy-projects/**", "temp-projects/**"]}]}
- Use the
If you disabled inference to use explicit project.json files:
- The new plugin will still detect your projects via
.csprojfiles - You can keep
project.jsonfiles to customize targets, but they're optional - Consider removing them to use the automatically inferred targets
- The new plugin will still detect your projects via
Configuration Changes
Section titled “Configuration Changes”Module Boundaries → Nx Conformance
Section titled “Module Boundaries → Nx Conformance”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.
NuGet Package Management
Section titled “NuGet Package Management”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" />Testing the Migration
Section titled “Testing the Migration”Run these commands to verify everything works:
# Clear cachenx reset
# Verify project detectionnx show projects
# Test buildsnx run-many -t build
# Test affected buildsnx affected -t build
# Run testsnx run-many -t testTroubleshooting
Section titled “Troubleshooting”Projects Not Detected After Migration
Section titled “Projects Not Detected After Migration”Symptom: Some .NET projects don't appear in nx show projects
Solution:
- Ensure project files have
.csproj,.fsproj, or.vbprojextensions - Check that the plugin is registered in
nx.json - Run
nx resetto clear the cache
"Could not find project reference" Build Error
Section titled “"Could not find project reference" Build Error”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
.csprojfiles use correct relative paths - Run
nx resetto clear stale cache
Missing Targets (test, pack, publish)
Section titled “Missing Targets (test, pack, publish)”Symptom: Expected targets like test or pack don't show up
Solution:
test: Only created for projects withIsTestProjectproperty orMicrosoft.NET.Test.Sdkpackagepack: Only created for library projects (not executables)publish: Only created for executable projects (OutputType="Exe")- Use
nx show project my-projectto see all available targets
Project Name Mismatch After Migration
Section titled “Project Name Mismatch After Migration”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>Next Steps
Section titled “Next Steps”After completing the migration:
- Review the incremental builds guide to understand how
--no-dependenciesoptimizes 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