{"id":57419,"date":"2025-07-29T11:05:00","date_gmt":"2025-07-29T18:05:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=57419"},"modified":"2025-11-24T11:32:53","modified_gmt":"2025-11-24T19:32:53","slug":"announcing-aspire-9-4","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-aspire-9-4\/","title":{"rendered":"Aspire 9.4 is here with a CLI and interactive dashboard features"},"content":{"rendered":"<p>Today, we released Aspire 9.4, our biggest release <em>ever<\/em>, bringing new integrations, interactive dashboard-based inputs, and a standalone, native AOT command line tool for creating and running Aspirified apps. We also published our <a href=\"https:\/\/github.com\/dotnet\/aspire\/discussions\/10644\">first roadmap<\/a> last week, which outlines a bunch of exciting features we want to tackle in the next 6 months. There are too many things in this release for me to cover in one blog, so I picked some of my favorites to share &#8211; you can see the rest in our <a href=\"https:\/\/learn.microsoft.com\/dotnet\/aspire\/whats-new\/dotnet-aspire-9.4\">What&#8217;s New docs<\/a>.<\/p>\n<h2>\u26a1Just clone and &#8220;aspire run&#8221; with the new Aspire CLI<\/h2>\n<p>With Aspire 9.4, the Aspire CLI is <strong>officially GA<\/strong> and here to make your dev loop even more seamless. The CLI gives you a fast, scriptable, and consistent way to scaffold, run, and configure your apps.<\/p>\n<p>This release brings the first four core commands:<\/p>\n<ul>\n<li><code>aspire new<\/code> \u2013 Choose from our set of templates to kickstart your app<\/li>\n<li><code>aspire add<\/code> \u2013 Add Aspire hosting integrations from anywhere in your repo<\/li>\n<li><code>aspire run<\/code> \u2013 Run your full app stack from any terminal or editor (or subdirectory!)<\/li>\n<li><code>aspire config<\/code> \u2013 View, set, and change CLI settings and feature flags &#8211; local to your repo or global to your machine<\/li>\n<\/ul>\n<p><div style=\"width: 640px;\" class=\"wp-video\"><video class=\"wp-video-shortcode\" id=\"video-57419-1\" width=\"640\" height=\"360\" preload=\"metadata\" controls=\"controls\"><source type=\"video\/webm\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/07\/AspireCLI-BlogDemo.webm?_=1\" \/><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/07\/AspireCLI-BlogDemo.webm\">https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/07\/AspireCLI-BlogDemo.webm<\/a><\/video><\/div><\/p>\n<p>We&#8217;re also including an updated version of <code>aspire publish<\/code>, which is still in preview, and two commands in beta &#8211; <code>exec<\/code> (for executing CLI tools like database migrations) and <code>deploy<\/code> (for deploying your full stack to dev, test, or even prod environments). The two beta commands can be turned on via <code>aspire config set<\/code> &#8211; see the CLI Reference docs for more details.<\/p>\n<p>The CLI is native AOT (ahead-of-time) compiled, making it super fast across different architectures. You can download the GA CLI from our install script:<\/p>\n<pre><code class=\"language-bash\"># Bash\ncurl -sSL https:\/\/aspire.dev\/install.sh | bash\n\n# Powershell\niex \"&amp; { $(irm https:\/\/aspire.dev\/install.ps1) }\"<\/code><\/pre>\n<p><div class=\"alert alert-primary\"><p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Info\"><\/i><strong>Note<\/strong><\/p>You can continue using the Aspire CLI as a dotnet tool, but it will not be the AOT version. If you&#8217;re currently using the dotnet tool and would like to update to the AOT version, first uninstall it with <code>dotnet tool uninstall -g aspire.cli<\/code>.<\/div><\/p>\n<p>Learn more about the Aspire CLI in our <a href=\"https:\/\/learn.microsoft.com\/dotnet\/aspire\/cli\/overview\">docs<\/a>.<\/p>\n<h2>\ud83d\uddb1\ufe0f Custom dashboard interactivity<\/h2>\n<p>With Aspire, you can tailor the dashboard to your specific application with <a href=\"https:\/\/learn.microsoft.com\/dotnet\/aspire\/fundamentals\/custom-resource-commands\">custom resource commands<\/a> and <a href=\"https:\/\/learn.microsoft.com\/dotnet\/aspire\/fundamentals\/custom-resource-urls\">named URLs<\/a>, and the ability to hook into resource <a href=\"https:\/\/learn.microsoft.com\/dotnet\/aspire\/app-host\/eventing\">lifecycle events<\/a>. Aspire 9.4 brings a user-friendly overhaul to our eventing APIs and a major new extensibility point for you to leverage &#8211; the interaction service.<\/p>\n<p>With the interaction service, you can create custom UX to get user input during development while the app is running, present notifications, or ask for confirmation before running a command. The interaction service supports 5 different input types:<\/p>\n<ul>\n<li>Text (Standard text input &#8211; great for passing args, creating mock data, etc)<\/li>\n<li>SecretText (Masked text input &#8211; great for API keys, tokens, etc)<\/li>\n<li>Number (Numeric input &#8211;  great for seeding DB items, running load tests)<\/li>\n<li>Choice (Dropdown from a set list &#8211; useful for structured inputs)<\/li>\n<li>Boolean (Checkbox &#8211; great for toggling on things like mock data at runtime)<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/11\/dashboard-interaction.webp\" alt=\"a screenshot of the aspire dashboard with a new modal &quot;input request&quot; asking for a name, password, dinner type, and number\" \/><\/p>\n<p>The interaction service also works in the CLI for inputs required during publish and deploy.<\/p>\n<p><div class=\"alert alert-primary\"><p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Info\"><\/i><strong>Preview Feature<\/strong><\/p>The interaction service is <strong>still in preview<\/strong> and the API may change as we refine it further. We&#8217;re looking forward to hearing your feedback about it on the <a href=\"https:\/\/github.com\/dotnet\/aspire\">Aspire GitHub<\/a>!<\/div><\/p>\n<h3>Built-in prompting for parameters<\/h3>\n<p>Aspire 9.4 already leverages the new interaction service to collect any missing parameter values defined in your apphost. Instead of expecting every dev on your team to maintain their own local <code>appsettings.development.json<\/code> or <code>.env<\/code> file, Aspire will prompt for missing values in the dashboard before starting any resource that needs them. You can even customize parameter descriptions with rich markdown, so anyone who clones and runs your app has clear guidance on what values they need to provide &#8211; and then optionally save those values to their user secrets for non-source-controlled per-project config.<\/p>\n<h2>Easy AI development with GitHub Models and Azure AI Foundry<\/h2>\n<p>Aspire streamlines distributed, complex app dev, and an increasingly popular example of this is AI development. If you&#8217;ve been adding agentic workflows, chatbots, or other AI-enabled experiences to your stacks, you know how difficult it is to try different models, wire them up, deploy them (and authenticate to them!) at dev time, and figure out what&#8217;s actually happening while you debug. But, AI-enabled apps are really just distributed apps with a new type of container &#8211; an AI model! &#8211; which means Aspire is perfect for streamlining this dev loop.<\/p>\n<p>Aspire 9.4 includes two new AI-focused hosting integrations &#8211; <a href=\"https:\/\/learn.microsoft.com\/dotnet\/aspire\/github\/github-models-integration\">GitHub Models (Preview)<\/a> and <a href=\"https:\/\/learn.microsoft.com\/dotnet\/aspire\/azureai\/azureai-foundry-integration\">Azure AI Foundry (Preview)<\/a> &#8211; which let you define AI models in your apphost then run them locally or deploy models to develop against. Both integrations work seamlessly with the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/aspire\/azureai\/azureai-inference-integration\">Azure AI Inference (Preview) client integration<\/a>, so you get detailed OpenTelemetry traces and simple bootstrapping code for your client app or service implementing it.<\/p>\n<p>This is all the code it takes to define, deploy, and run a new GitHub or Azure AI Foundry model in your apphost:<\/p>\n<pre><code class=\"language-csharp\">\/\/ AppHost.cs\nvar ai = builder.AddAzureAIFoundry(\"ai\");\n\nvar embedding = ai.AddDeployment(\n    name: \"text-embedding\",\n    modelName: \"text-embedding-3-small\",\n    modelVersion: \"1\",\n    format: \"OpenAI\")\n     .WithProperties(d =&gt;\n        {\n            d.SkuCapacity = 20;\n        });<\/code><\/pre>\n<h2>Yet another resource with ExternalService and the updated YARP integration<\/h2>\n<p>One of my favorite features in 9.4 seems minor, but is a huge quality of life improvement for anyone working with external or third-party APIs. You can now use <code>AddExternalService()<\/code> to <a href=\"https:\/\/learn.microsoft.com\/dotnet\/aspire\/fundamentals\/orchestrate-resources#express-external-service-resources\">model any URL or endpoint as a resource<\/a>, get health status, and reference or configure it the same as any other resource in the apphost.<\/p>\n<pre><code class=\"language-csharp\">var externalApi = builder.AddExternalService(\"resource-name\", \"https:\/\/api.example.com\");\n\nvar frontend = builder.AddNpmApp(\"frontend\", \"..\/MyJSCodeDirectory\")\n    .WithReference(externalApi);<\/code><\/pre>\n<p>Many external APIs require some sort of auth or specific headers, versioning, or routes. The preview <a href=\"https:\/\/learn.microsoft.com\/dotnet\/aspire\/proxies\/yarp-integration\">YARP integration<\/a> has been updated with fluent transform APIs so you can programmatically define your config in C# with strong types, IntelliSense, and any other Aspire resource config.<\/p>\n<h2>Start using 9.4 today<\/h2>\n<p>There are <em>so many<\/em> more features, integration updates, and quality-of-life improvements that shipped in Aspire 9.4 &#8211; if I tried to cover them all, I&#8217;d be reaching <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/performance-improvements-in-net-9\/\">Stephen Toub-level<\/a> post length! You can see a comprehensive list of changes in our <a href=\"https:\/\/learn.microsoft.com\/dotnet\/aspire\/whats-new\/dotnet-aspire-9.4\">What&#8217;s New<\/a> doc, and use them now by updating your AppHost.csproj SDK version and packages:<\/p>\n<pre><code class=\"language-xml\">&lt;!-- SDK version --&gt;\n&lt;Sdk Name=\"Aspire.AppHost.Sdk\" Version=\"9.4.0\" \/&gt;\n\n&lt;!-- NuGet package references --&gt;\n&lt;PackageReference Include=\"Aspire.Hosting.AppHost\" Version=\"9.4.0\" \/&gt;<\/code><\/pre>\n<p>I&#8217;m so proud of this release and the incredible amount of work that went into it &#8211; both from the Aspire team and our <a href=\"https:\/\/github.com\/dotnet\/aspire\/pulls?q=is%3Apr+is%3Aclosed+label%3Acommunity-contribution+closed%3A%3E2025-05-30\">community contributors<\/a>. We&#8217;re looking forward to hearing your feedback on 9.4 and what you want to see next &#8211; let us know on <a href=\"https:\/\/github.com\/dotnet\/aspire\">GitHub<\/a> and our <a href=\"https:\/\/aka.ms\/dotnet\/aspire\">new Discord server<\/a>. See you there!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Aspire 9.4 is packed with new features, integrations, and improvements<\/p>\n","protected":false},"author":1965,"featured_media":58989,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,7783,7254],"tags":[7768,7174,63],"class_list":["post-57419","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-aspire","category-featured","tag-aspire","tag-cli","tag-dotnet"],"acf":[],"blog_post_summary":"<p>Aspire 9.4 is packed with new features, integrations, and improvements<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/57419","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/1965"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=57419"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/57419\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58989"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=57419"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=57419"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=57419"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}