Skip to content

Commit 184fa3e

Browse files
Add article for RID-specific, self-contained and AOT .NET tools (#49874)
* Initial plan * Add RID-specific and AOT .NET tools documentation Co-authored-by: meaghanlewis <10103121+meaghanlewis@users.noreply.github.com> * article updates * add article to TOC * edit pass * fix broken link * address review feedback --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: meaghanlewis <10103121+meaghanlewis@users.noreply.github.com> Co-authored-by: Meaghan Osagie <mosagie@microsoft.com>
1 parent 9b217d6 commit 184fa3e

File tree

4 files changed

+219
-0
lines changed

4 files changed

+219
-0
lines changed

docs/core/tools/global-tools-how-to-create.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,7 @@ If you prefer, you can skip the global tools tutorial and go directly to the loc
226226

227227
> [!div class="nextstepaction"]
228228
> [Install and use a local tool](local-tools-how-to-use.md)
229+
230+
## See also
231+
232+
- [Create RID-specific and AOT .NET tools](rid-specific-tools.md)

docs/core/tools/global-tools.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,3 +300,4 @@ dotnet <command> --help
300300
* [Tutorial: Create a .NET tool using the .NET CLI](global-tools-how-to-create.md)
301301
* [Tutorial: Install and use a .NET global tool using the .NET CLI](global-tools-how-to-use.md)
302302
* [Tutorial: Install and use a .NET local tool using the .NET CLI](local-tools-how-to-use.md)
303+
* [Create RID-specific and AOT .NET tools](rid-specific-tools.md)
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
---
2+
title: Create RID-specific, self-contained, and AOT .NET tools
3+
description: Learn how to create and package RID-specific, self-contained, and AOT .NET tools for platform-specific distribution.
4+
ms.topic: how-to
5+
ms.date: 11/12/2025
6+
ai-usage: ai-assisted
7+
---
8+
9+
# Create RID-specific, self-contained, and AOT .NET tools
10+
11+
**This article applies to:** ✔️ .NET SDK 10 and later versions
12+
13+
Package .NET tools for specific platforms and architectures so you can distribute 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.
14+
15+
## Overview
16+
17+
Starting with .NET SDK 10, you can create .NET tools that target specific Runtime Identifiers (RIDs). These tools can be:
18+
19+
- **RID-specific**: Compiled for particular operating systems and architectures.
20+
- **Self-contained**: Include the .NET runtime and don't require a separate .NET installation.
21+
- **Native AOT**: Use Ahead-of-Time compilation for faster startup and smaller memory footprint.
22+
23+
When users install a RID-specific tool, the .NET CLI automatically selects and installs the appropriate package for their platform.
24+
25+
## Opt in to RID-specific packaging
26+
27+
To create a RID-specific tool, configure your project with one of the following MSBuild properties:
28+
29+
### RuntimeIdentifiers property
30+
31+
Use `RuntimeIdentifiers` to specify the platforms your tool supports:
32+
33+
```xml
34+
<Project Sdk="Microsoft.NET.Sdk">
35+
<PropertyGroup>
36+
<OutputType>Exe</OutputType>
37+
<TargetFramework>net10.0</TargetFramework>
38+
<PackAsTool>true</PackAsTool>
39+
<ToolCommandName>mytool</ToolCommandName>
40+
<RuntimeIdentifiers>win-x64;linux-x64;osx-arm64</RuntimeIdentifiers>
41+
</PropertyGroup>
42+
</Project>
43+
```
44+
45+
### ToolPackageRuntimeIdentifiers property
46+
47+
Alternatively, use `ToolPackageRuntimeIdentifiers` for tool-specific RID configuration:
48+
49+
```xml
50+
<Project Sdk="Microsoft.NET.Sdk">
51+
<PropertyGroup>
52+
<OutputType>Exe</OutputType>
53+
<TargetFramework>net10.0</TargetFramework>
54+
<PackAsTool>true</PackAsTool>
55+
<ToolCommandName>mytool</ToolCommandName>
56+
<ToolPackageRuntimeIdentifiers>win-x64;linux-x64;osx-arm64</ToolPackageRuntimeIdentifiers>
57+
</PropertyGroup>
58+
</Project>
59+
```
60+
61+
Use a semicolon-delimited list of RID values. For a list of Runtime Identifiers, see the [RID catalog](../rid-catalog.md).
62+
63+
## Package your tool
64+
65+
The packaging process differs depending on whether you're using AOT compilation. To build a NuGet package, or *.nupkg* file from the project, run the [dotnet pack](dotnet-pack.md) command.
66+
67+
### RID-specific and self-contained tools
68+
69+
For tools without AOT compilation, run `dotnet pack` once:
70+
71+
```dotnetcli
72+
dotnet pack
73+
```
74+
75+
This command creates multiple NuGet packages:
76+
77+
- One package for each RID: `<packageName>.<RID>.<packageVersion>.nupkg`
78+
- Example: `mytool.win-x64.1.0.0.nupkg`
79+
- Example: `mytool.linux-x64.1.0.0.nupkg`
80+
- Example: `mytool.osx-arm64.1.0.0.nupkg`
81+
- One RID-agnostic pointer package: `<packageName>.<packageVersion>.nupkg`
82+
- Example: `mytool.1.0.0.nupkg`
83+
84+
### AOT tools
85+
86+
For tools with AOT compilation (`<PublishAot>true</PublishAot>`), you must pack separately for each platform:
87+
88+
- Pack the top-level package once (on any platform):
89+
90+
```dotnetcli
91+
dotnet pack
92+
```
93+
94+
- Pack for each specific RID on the corresponding platform:
95+
96+
```dotnetcli
97+
dotnet pack -r win-x64
98+
dotnet pack -r linux-x64
99+
dotnet pack -r osx-arm64
100+
```
101+
102+
You must run each RID-specific pack command on the matching platform because AOT compilation produces native binaries. For more information about the prerequisites for Native AOT compilation, see [Native AOT deployment](../deploying/native-aot/index.md).
103+
104+
## Package structure
105+
106+
### Package types
107+
108+
RID-specific tool packages use two package types:
109+
110+
- **DotnetTool**: The top-level package that contains metadata.
111+
- **DotnetToolRidPackage**: The RID-specific packages that contain the actual tool binaries.
112+
113+
### Package metadata
114+
115+
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.
116+
117+
## Publish your tool
118+
119+
Publish all packages to NuGet.org or your package feed by using [dotnet nuget push](dotnet-nuget-push.md):
120+
121+
```dotnetcli
122+
dotnet nuget push path/to/package/root/*.nupkg
123+
```
124+
125+
## Run a RID-specific tool
126+
127+
Users run RID-specific tools the same way as platform-agnostic tools:
128+
129+
```dotnetcli
130+
dnx mytool
131+
```
132+
133+
The CLI automatically:
134+
135+
1. Downloads the top-level package.
136+
1. Reads the RID-specific metadata.
137+
1. Identifies the most appropriate package for the current platform.
138+
1. Downloads and runs the RID-specific package.
139+
140+
## Example: Create an AOT tool
141+
142+
Here's a complete example of creating an AOT-compiled RID-specific tool:
143+
144+
1. Create a new console application:
145+
146+
```dotnetcli
147+
dotnet new console -n MyFastTool
148+
cd MyFastTool
149+
```
150+
151+
1. Update the project file to enable AOT and RID-specific packaging:
152+
153+
```xml
154+
<Project Sdk="Microsoft.NET.Sdk">
155+
<PropertyGroup>
156+
<OutputType>Exe</OutputType>
157+
<TargetFramework>net10.0</TargetFramework>
158+
<PackAsTool>true</PackAsTool>
159+
<ToolCommandName>myfasttool</ToolCommandName>
160+
<RuntimeIdentifiers>win-x64;linux-x64;osx-arm64</RuntimeIdentifiers>
161+
<PublishAot>true</PublishAot>
162+
<PackageId>MyFastTool</PackageId>
163+
<Version>1.0.0</Version>
164+
<Authors>Your Name</Authors>
165+
<Description>A fast AOT-compiled tool</Description>
166+
</PropertyGroup>
167+
</Project>
168+
```
169+
170+
1. Add your application code in `Program.cs`:
171+
172+
```csharp
173+
Console.WriteLine("Hello from MyFastTool!");
174+
Console.WriteLine($"Running on {Environment.OSVersion}");
175+
```
176+
177+
1. Pack the top-level package:
178+
179+
```dotnetcli
180+
dotnet pack
181+
```
182+
183+
1. Pack for each specific RID (on the corresponding platform):
184+
185+
On Windows:
186+
187+
```dotnetcli
188+
dotnet pack -r win-x64
189+
```
190+
191+
On Linux:
192+
193+
```dotnetcli
194+
dotnet pack -r linux-x64
195+
```
196+
197+
On macOS:
198+
199+
```dotnetcli
200+
dotnet pack -r osx-arm64
201+
```
202+
203+
1. Publish all packages to NuGet.org by using the [dotnet nuget push](dotnet-nuget-push.md) command.
204+
205+
## See also
206+
207+
- [Tutorial: Create a .NET tool](global-tools-how-to-create.md)
208+
- [.NET tools overview](global-tools.md)
209+
- [dotnet pack command](dotnet-pack.md)
210+
- [RID catalog](../rid-catalog.md)
211+
- [Native AOT deployment](../deploying/native-aot/index.md)

docs/navigate/tools-diagnostics/toc.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,9 @@ items:
314314
- name: Manage tools
315315
displayName: global tool,local tool
316316
href: ../../core/tools/global-tools.md
317+
- name: RID-specific, self-contained, and AOT tools
318+
displayName: rid-specific tool,self-contained tool,aot tool
319+
href: ../../core/tools/rid-specific-tools.md
317320
- name: Troubleshoot tools
318321
displayName: global tool troubleshooting,local tool troubleshooting,
319322
href: ../../core/tools/troubleshoot-usage-issues.md

0 commit comments

Comments
 (0)