-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Add article for RID-specific, self-contained and AOT .NET tools #49874
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 4 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
6f22267
Initial plan
Copilot 95b4e13
Add RID-specific and AOT .NET tools documentation
Copilot dba0403
article updates
meaghanlewis 8c65aa8
add article to TOC
meaghanlewis ba84d0d
edit pass
meaghanlewis ab9fe4f
fix broken link
meaghanlewis 5d019b2
address review feedback
meaghanlewis File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,214 @@ | ||
| --- | ||
| title: Create RID-specific, self-contained, and AOT .NET tools | ||
| description: Learn how to create and package RID-specific, self-contained and AOT .NET tools for platform-specific distribution. | ||
| ms.topic: how-to | ||
| ms.date: 11/12/2025 | ||
| ai-usage: ai-assisted | ||
| --- | ||
|
|
||
| # Create RID-specific, self-contained, and AOT .NET tools | ||
|
|
||
| **This article applies to:** ✔️ .NET SDK 10 and later versions | ||
|
|
||
| .NET tools can be packaged for specific platforms and architectures, enabling distribution of native, fast, and trimmed applications. This capability makes it easier to distribute native, fast, trimmed .NET applications for command-line tools like MCP servers or other platform-specific utilities. | ||
|
|
||
| ## Overview | ||
|
|
||
| Starting with .NET SDK 10, you can create .NET tools that target specific Runtime Identifiers (RIDs). These tools can be: | ||
|
|
||
| - **RID-specific**: Compiled for particular operating systems and architectures. | ||
| - **Self-contained**: Include the .NET runtime and don't require a separate .NET installation. | ||
| - **AOT-compiled**: Use Ahead-of-Time compilation for faster startup and smaller memory footprint. | ||
|
|
||
| When users install a RID-specific tool, the .NET CLI automatically selects and installs the appropriate package for their platform. | ||
|
|
||
| ## Opt in to RID-specific packaging | ||
|
|
||
| To create a RID-specific tool, configure your project with one of the following MSBuild properties: | ||
|
|
||
| ### RuntimeIdentifier property | ||
|
|
||
| Use `RuntimeIdentifier` to specify the platforms your tool supports: | ||
meaghanlewis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ```xml | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>net9.0</TargetFramework> | ||
| <PackAsTool>true</PackAsTool> | ||
| <ToolCommandName>mytool</ToolCommandName> | ||
| <RuntimeIdentifier>win-x64;linux-x64;osx-arm64</RuntimeIdentifier> | ||
meaghanlewis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| </PropertyGroup> | ||
| </Project> | ||
| ``` | ||
|
|
||
| ### ToolPackageRuntimeIdentifier property | ||
|
|
||
| Alternatively, use `ToolPackageRuntimeIdentifier` for tool-specific RID configuration: | ||
meaghanlewis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ```xml | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>net9.0</TargetFramework> | ||
| <PackAsTool>true</PackAsTool> | ||
| <ToolCommandName>mytool</ToolCommandName> | ||
| <ToolPackageRuntimeIdentifier>win-x64;linux-x64;osx-arm64</ToolPackageRuntimeIdentifier> | ||
meaghanlewis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| </PropertyGroup> | ||
| </Project> | ||
| ``` | ||
|
|
||
| Use a semicolon-delimited list of RID values. For a list of Runtime Identifiers, see the [RID catalog](../rid-catalog.md). | ||
|
|
||
| ## Package your tool | ||
|
|
||
| The packaging process differs depending on whether you're using AOT compilation. | ||
|
|
||
| ### Non-AOT tools | ||
|
|
||
| For tools without AOT compilation, run `dotnet pack` once: | ||
|
|
||
| ```dotnetcli | ||
| dotnet pack | ||
| ``` | ||
|
|
||
| This command creates multiple NuGet packages: | ||
|
|
||
| - One package for each RID: `<packageName>.<RID>.<packageVersion>.nupkg` | ||
| - Example: `mytool.win-x64.1.0.0.nupkg` | ||
| - Example: `mytool.linux-x64.1.0.0.nupkg` | ||
| - Example: `mytool.osx-arm64.1.0.0.nupkg` | ||
meaghanlewis marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| - One RID-agnostic pointer package: `<packageName>.<packageVersion>.nupkg` | ||
| - Example: `mytool.1.0.0.nupkg` | ||
meaghanlewis marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ### AOT tools | ||
|
|
||
| For tools with AOT compilation (`<PublishAot>true</PublishAot>`), you must pack separately for each platform: | ||
|
|
||
| 1. Pack the top-level package once (on any platform): | ||
|
|
||
| ```dotnetcli | ||
| dotnet pack | ||
| ``` | ||
|
|
||
| 2. Pack for each specific RID on the corresponding platform: | ||
|
|
||
| ```dotnetcli | ||
| dotnet pack -r win-x64 | ||
| dotnet pack -r linux-x64 | ||
| dotnet pack -r osx-arm64 | ||
| ``` | ||
|
|
||
| You must run each RID-specific pack command on the matching platform because AOT compilation produces native binaries. | ||
meaghanlewis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Package structure | ||
|
|
||
| ### Package types | ||
|
|
||
| RID-specific tool packages use two package types: | ||
|
|
||
| - **DotnetTool**: The top-level package that contains metadata | ||
| - **DotnetToolRidPackage**: The RID-specific packages that contain the actual tool binaries | ||
meaghanlewis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ### Package metadata | ||
|
|
||
| The top-level package includes metadata that signals it's a RID-specific tool and lists the RID-specific packages. When you run `dotnet tool install`, the CLI reads this metadata to determine which RID-specific package to install for the current platform. | ||
|
|
||
| ## Publish your tool | ||
|
|
||
| Publish all packages to NuGet.org or your package feed: | ||
|
|
||
| ```dotnetcli | ||
| dotnet nuget push mytool.1.0.0.nupkg | ||
meaghanlewis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| dotnet nuget push mytool.win-x64.1.0.0.nupkg | ||
| dotnet nuget push mytool.linux-x64.1.0.0.nupkg | ||
| dotnet nuget push mytool.osx-arm64.1.0.0.nupkg | ||
| ``` | ||
|
|
||
| ## Install a RID-specific tool | ||
|
|
||
| Users install RID-specific tools the same way as regular tools: | ||
|
|
||
| ```dotnetcli | ||
| dotnet tool install -g mytool | ||
| ``` | ||
|
|
||
| The CLI automatically: | ||
|
|
||
| 1. Downloads the top-level package. | ||
| 1. Reads the RID-specific metadata. | ||
| 1. Identifies the most appropriate package for the current platform. | ||
| 1. Downloads and installs the RID-specific package. | ||
meaghanlewis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Example: Create an AOT tool | ||
|
|
||
| Here's a complete example of creating an AOT-compiled RID-specific tool: | ||
|
|
||
| 1. Create a new console application: | ||
|
|
||
| ```dotnetcli | ||
| dotnet new console -n MyFastTool | ||
| cd MyFastTool | ||
| ``` | ||
|
|
||
| 2. Update the project file to enable AOT and RID-specific packaging: | ||
|
|
||
| ```xml | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>net9.0</TargetFramework> | ||
| <PackAsTool>true</PackAsTool> | ||
| <ToolCommandName>myfasttool</ToolCommandName> | ||
| <RuntimeIdentifiers>win-x64;linux-x64;osx-arm64</RuntimeIdentifiers> | ||
| <PublishAot>true</PublishAot> | ||
| <PackageId>MyFastTool</PackageId> | ||
| <Version>1.0.0</Version> | ||
| <Authors>Your Name</Authors> | ||
| <Description>A fast AOT-compiled tool</Description> | ||
| </PropertyGroup> | ||
| </Project> | ||
| ``` | ||
|
|
||
| 3. Add your application code in `Program.cs`: | ||
|
|
||
| ```csharp | ||
| Console.WriteLine("Hello from MyFastTool!"); | ||
| Console.WriteLine($"Running on {Environment.OSVersion}"); | ||
| ``` | ||
|
|
||
| 4. Pack the top-level package: | ||
|
|
||
| ```dotnetcli | ||
| dotnet pack | ||
| ``` | ||
|
|
||
| 5. Pack for each specific RID (on the corresponding platform): | ||
|
|
||
| On Windows: | ||
|
|
||
| ```dotnetcli | ||
| dotnet pack -r win-x64 | ||
| ``` | ||
|
|
||
| On Linux: | ||
|
|
||
| ```dotnetcli | ||
| dotnet pack -r linux-x64 | ||
| ``` | ||
|
|
||
| On macOS: | ||
|
|
||
| ```dotnetcli | ||
| dotnet pack -r osx-arm64 | ||
| ``` | ||
|
|
||
| 6. Publish all packages to NuGet.org. | ||
|
|
||
| ## See also | ||
|
|
||
| - [Tutorial: Create a .NET tool](global-tools-how-to-create.md) | ||
| - [.NET tools overview](global-tools.md) | ||
| - [dotnet pack command](dotnet-pack.md) | ||
| - [RID catalog](../rid-catalog.md) | ||
| - [Native AOT deployment](../deploying/native-aot/index.md) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.