Development·

.NET Aspirations - Tailor It To Your Stack

Using .NET Aspire with a Nuxt front end

You might have already seen blog posts and videos showing how .NET Aspire can enhance our local development environment, using an example with a Blazor SPA and an ASP.NET Core API. However, not everyone uses Blazor; many prefer a JavaScript framework for front-end development.

Fortunately, we can still benefit from .NET Aspire regardless of our stack. In this article, we will explore how to use .NET Aspire to develop an application composed of an ASP.NET Core back end and a Nuxt front end.

The context

The context is very basic: developing a web application with an ASP.NET Core API for the back end and a Nuxt application for the front end. The Nuxt application calls the ASP.NET Core API to get data to show on the website.

The goal is to easily run the back end and front end together locally. While using .NET Aspire is not necessary for this, .NET Aspire orchestration can simplify the process and help address some common issues.

What problems are we trying to solve?

  1. No “F5 experience” ➡️ you have to start everything separately instead of just pressing "F5" to run everything at once.
  2. Logs are available in the separate terminals where you started the back end and front end, not in a single location
  3. To call the back end from the front end, we have to hard-code the API URL in the front-end configuration

Set up the application

We can use this application I created to showcase how to integrate ASP.NET Core with Nuxt in a previous article. It uses the ASP.NET Core Web API template and the Nuxt 3 with v4 compact template with very few modifications so it’s very basic: a front displaying weather forecasts retrieved from the API. You can clone the GitHub repository (use tag initial-without-aspire) or start from scratch following the step-by-step guide from this article.

A table showing dates with weather summaries and temperatures in Celsius and Fahrenheit.

Add .NET Aspire to our existing project

Since .NET 9, we no longer need to install a specific workload for .NET Aspire. We only need to install the .NET Aspire templates, as they make it easier to add .NET Aspire to our application.

dotnet new install Aspire.ProjectTemplates

Now, we can create a new app host project to orchestrate the different parts of our application (the WebApp in Nuxt.js and the WebApiin ASP.NET Core).

dotnet new aspire-apphost -o AppHost
dotnet sln AspnetWithNuxt.slnx add AppHost\AppHost.csproj

At the moment, the Program.cs file of the app host project doesn't contain much, so we need to modify it to declare two resources (one for the WebApiand one for WebApp). This way, when executing the app host, it will handle running both of them.

For the WebApi

Since the WebApi project is in .NET and part of the same solution as the app host, it's quite straightforward:

  1. We add the WebApi as a project reference in the app host project
    dotnet add .\AppHost\AppHost.csproj reference .\WebApi\WebApi.csproj
    

    This will trigger a source generator that will create a class representing the WebApiproject by its name with its path.
    // <auto-generated/>
    
    namespace Projects;
    
    [global::System.CodeDom.Compiler.GeneratedCode("Aspire.Hosting", null)]
    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage(Justification = "Generated code.")]
    [global::System.Diagnostics.DebuggerDisplay("Type = {GetType().Name,nq}, ProjectPath = {ProjectPath}")]
    public class WebApi : global::Aspire.Hosting.IProjectMetadata
    {
        public string ProjectPath => """D:\Learning\ASP.NET\AspnetWithNuxt\WebApi\WebApi.csproj""";
    }
    
  2. We declare the project resource WebApi in the Program.cs file of the app host with the following code
AppHost/Program.cs
var webApi = builder.AddProject<Projects.WebApi>("WebApi");

Thanks to the source generated WebApi class in the Projects namespace, we don’t have to specify its path.

For the WebApp

We can use an integration from the Aspire Community toolkit which contains community-driven integrations for .NET Aspire, including one for Vite applications like my Nuxt project.

dotnet add AppHost\AppHost.csproj package CommunityToolkit.Aspire.Hosting.NodeJS.Extensions

We can declare the Vite App resource in the Program.cs file of the app host by specifying the path of the Nuxt app:

AppHost/Program.cs
var webApp= builder.AddViteApp("WebApp", "../WebApp", "pnpm")
    .WithPnpmPackageInstallation()
    .WaitFor(webApi);
  • AddViteApp let us specify the package manager we want to use, pnpm here
  • WithPnpmPackageInstallation ensures dependencies are already installed before starting the app
  • WaitFor ensures the WebApi is running before starting the WebApp

The only downside of using AddViteApp is that it doesn't currently support exposing the HTTPS endpoint. So, even though the WebApp will be launched by the AppHost and will work correctly with HTTPS, its URL in the .NET Aspire dashboard will be in HTTP. This isn't a major issue; you could just replace the http in the URL by https. But let’s fix that anyway to use another method AddPnpmApp (there are other methods like AddNpmApp for other package manager) of the Aspire Community toolkit instead:

AppHost/Program.cs
var webApp= builder.AddPnpmApp("WebApp", "../WebApp", "dev")
    .WithHttpsEndpoint(env: "PORT")
    .WithExternalHttpEndpoints()
    .WithPnpmPackageInstallation();
You don’t need to know exactly what AddPnpmApp does behind the scenes, but it might be helpful to check out (use your IDE to access the decompiled code with F12). I’ve heard people like Scott Hanselman and Mark Russinovich say that we should try to “understand how things work one level below the level we are operating on”, and I find this very true. In the end, the PnpmAdd resource is just an executable resource called with specific commands and parameters.

Running the AppHost with the .NET Aspire dashboard

If we run the AppHost now, it will start the WebApp and WebApi.

dotnet run --project AppHost/AppHost.csproj

The AppHost also launches the .NET Aspire dashboard where we can see the resources (here the WebApp and the WebApi) with their status and details about them like the endpoints and the environment variables.

Screenshot of the resources tab on the .NET Aspire dashboard.

There is also a console tab in the dashboard to visualize the console logs of the different resources.

Console logs showing the execution the WebApp in the Aspire dashboard.

Remove the hard-coded URL for the API

Everything is working properly, but the API URL is still hard-coded in the WebApp Nuxt configuration. To change that we will first need to add in the WebApp resource a reference to the WebApi resource.

AppHost/Program.cs
var webApp= builder.AddPnpmApp("WebApp", "../WebApp", "dev")
    .WithHttpsEndpoint(env: "PORT")
    .WithExternalHttpEndpoints()
    .WithPnpmPackageInstallation()
    .WithReference(webApi)
    .WaitFor(webApi);

.NET Aspire includes built-in support for service discovery, which automatically set the correct environment variables and connection strings when referencing resources properly.

Screenshot of the environment variables in .NET Aspire dashboard  for the WebApp resource.

Here, we can see that the endpoints of the WebApi have been automatically injected in the environment variables of the WebApp.

We can now get this environment variable using process.env.services__WebApi__https__0 or import.meta.env.services__WebApi__https__0 in the nuxtconfig.ts file:

nuxt.config.ts
  $development: {
    routeRules: {
      '/api/**': {
        proxy: `${import.meta.env.services__WebApi__https__0}/**`,
      }
    },

That’s great but that’s not a very explicit name. Let’s define another environment variable ApiUrl that will contain the url of the WebApi HTTPS endpoint and make it available to the WebApp:

AppHost/Program.cs
var webApp= builder.AddPnpmApp("WebApp", "../WebApp", "dev")
    .WithHttpsEndpoint(env: "PORT")
    .WithExternalHttpEndpoints()
    .WithPnpmPackageInstallation()
    .WithReference(webApi)
    .WaitFor(webApi)
    .WithEnvironment("ApiUrl", webApi.GetEndpoint("https"));

The route rules configuration in the nuxt.config.ts files becomes the following:

nuxt.config.ts
  $development: {
    routeRules: {
      '/api/**': {
        proxy: `${import.meta.env.ApiUrl}/**`,
      }
    },

And everything keep working fine.

Screenshot of the .NET Aspire dashboard showing the environment variable ApiUrl on the WebApp resource.

Final thoughts

We have seen how adding .NET Aspire to our project helped us solve the three problems we had: the lack of a unified start process, the need for a centralized place to view logs, and the possibility to remove the hard-coded API URL of our Nuxt configuration. The code for this article is available here.

Since .NET Aspire is highly customizable, it's easy to adjust it to fit our stack and needs. We focused on orchestrating the two resources we had but did not configure open telemetry. We'll discuss that in a future blog post.

In the meantime, keep learning!


The opinions expressed herein are my own and do not represent those of my employer or any other third-party views in any way.

Copyright © 2025 Alexandre Nédélec. All rights reserved.