README.md

October 21, 2025 ยท View on GitHub

dotnetsay

A platform-specific .NET SDK Tool demonstrating the use of .NET 10 preview 6 features

๐Ÿ“ Table of Contents

๐Ÿง About

.NET Tools are a useful way to distribute and use platform-independent executables. In .NET 10 we're adding a new way of packaging and using Tools that leans into platform-specificity. This can lead to smaller, faster, and more efficient tools that are tailored to the platform they run on, while still being easy to use and distribute.

This project is a demonstration of how to create a platform-specific .NET SDK Tool using the new features in .NET 10 preview 6. The tool uses Spectre.Console to echo back some input text as ASCII art.

๐Ÿ Getting Started

These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.

Prerequisites

๐ŸŽˆ Usage

To use the tool, use the new dnx command to run the tool from the command line. This will download and run the latest version of the tool, which will echo back the input text as ASCII art.

> dnx dotnetsay "Hello, World!"
Tool package dotnetsay@1.0.0 will be downloaded from source <source>.
Proceed? [y/n] (y): y
  _   _          _   _                __        __                 _       _   _
 | | | |   ___  | | | |   ___         \ \      / /   ___    _ __  | |   __| | | |
 | |_| |  / _ \ | | | |  / _ \         \ \ /\ / /   / _ \  | '__| | |  / _` | | |
 |  _  | |  __/ | | | | | (_) |  _      \ V  V /   | (_) | | |    | | | (_| | |_|
 |_| |_|  \___| |_| |_|  \___/  ( )      \_/\_/     \___/  |_|    |_|  \__,_| (_)
                                |/

๐Ÿš€ Packaging

The framework-dependent version of the tool, which will run on any system that has .NET 10 preview 6 runtimes installed, can be packaged using the dotnet pack command on the dotnetsay project. This will create a NuGet package in ./artifacts/package that can be distributed and installed using the dnx command. If you're testing the local build of the package, you can use the --source option to specify the local path to the package.

> dotnet pack dotnetsay
Restore complete (0.6s)
You are using a preview version of .NET. See: https://aka.ms/dotnet-support-policy
  dotnetsay net10.0 succeeded (0.2s) โ†’ artifacts\publish\dotnetsay\release\
  dotnetsay succeeded (3.4s) โ†’ artifacts\bin\dotnetsay\release\dotnetsay.dll

Build succeeded in 4.5s
> dotnet tool exec --source .\artifacts\package\ dotnetsay "Hello, World!"
  _   _          _   _                __        __                 _       _   _
 | | | |   ___  | | | |   ___         \ \      / /   ___    _ __  | |   __| | | |
 | |_| |  / _ \ | | | |  / _ \         \ \ /\ / /   / _ \  | '__| | |  / _` | | |
 |  _  | |  __/ | | | | | (_) |  _      \ V  V /   | (_) | | |    | | | (_| | |_|
 |_| |_|  \___| |_| |_|  \___/  ( )      \_/\_/     \___/  |_|    |_|  \__,_| (_)
                                |/

This package can be pushed to NuGet.org or another package source for easier use.

Variations

This tool builds in several variations to demonstrate the options you have for creating tools.

The variations are:

  • framework-dependent, platform-agnostic: This is the default variation, which will run on any system that has .NET 10 preview 6 runtimes installed. This is the way all .NET tools have been built in the past, and it will continue to work with the new dnx command. This will result in one tool package that can be used on any platform that supports .NET 10 preview 6.
  • framework-dependent, platform-specific: This variation will run on any system that has .NET 10 preview 6 runtimes installed, but it will only run on the specific platform it was built for. This is useful for tools that need to use platform-specific features or libraries. This will result in multiple tool packages, one for each platform that is specified in the project file. (NOTE: not working in p6, follow dotnet/sdk#49497 for updates)
  • self-contained, platform-specific: This variation will create a self-contained executable that includes the .NET runtime and all dependencies. This is useful for tools that need to run on systems that do not have .NET 10 preview 6 installed. This will result in multiple tool packages, one for each platform that is specified in the project file. In this mode, the tool packages may be fairly large.
  • trimmed, platform-specific: This variation will create a self-contained executable that includes the .NET runtime and all dependencies, but it will also trim unused code to reduce the size of the executable. This is useful for tools that need to run on systems that do not have .NET 10 preview 6 installed, but also need to be as small as possible. This will result in multiple self-contained executables, one for each platform that is specified in the project file. (NOTE: not working in p6, follow dotnet/sdk#49493 for updates)
  • Ahead-of-time (AOT) compiled, platform-specific: This variation will create a self-contained executable that is compiled ahead of time for the specific platform. This is useful for tools that need to run on systems that do not have .NET 10 preview 6 installed, but also need to have as little startup overhead as possible. This mode requires creating AOT'd tool packages for each platform that is specified in the project file. The AOT compilation process for .NET requires building on each destination platform, so this mode requires the use of a CI process like GitHub Actions or Azure DevOps to build the tool packages for each platform.

To build the variations, you use the dotnet pack command with the -p ToolType=<value> option to specify the variation you want to build. The valid values for ToolType are:

  • agnostic - one package, ~350kb
  • specific - one package per platform, ~350kb each
  • self-contained - one package per platform, ~35mb each
  • trimmed - one package per platform, ~10mb each
  • aot - one package per platform, 6mb ( with StripSymbols=true) each. in addition you must call dotnet pack -p ToolType=aot -r <rid> for each platform you want to build for, where <rid> is the runtime identifier for the platform. For example, dotnet pack -p ToolType=aot -r win-x64 will build an AOT'd tool package for Windows x64. See the build-aot-packages workflow for an example of how to build AOT'd tool packages for multiple platforms using GitHub Actions.