In this lab we will create the initial structure of the modular monolith application. We will mainly use the dotnet CLI tool, and you can script the setup once you're comfortable with it to suit your own team/org needs and standards.
When we're done, we will have a solution file called Nimble.Modulith.slnx which will contain five projects:
- AspireHost
- ServiceDefaults
- Web (ASP.NET Core app)
- Users
- Users.Contracts
Follow these steps to create the modular monolith solution from scratch. You can do this in a folder called labs (which is in the .gitignore file and so won't be added to git by default). If you want source control, create a new repo or use a subfolder called mylabs which should be tracked by git.
dotnet new sln --name Nimble.Modulith --output .This creates a Nimble.Modulith.slnx file in the repository root.
First, install the Aspire CLI if you haven't already:
dotnet tool install -g Aspire.Cli --prereleaseVerify the tool is installed:
aspire --versionshould yield 9.5.x
Then create the AspireHost and ServiceDefaults projects:
aspire new aspireWhen asked, give the name Nimble.Modulith. Keep the default output path. No tests.
cd Nimble.Modulith
dotnet sln migrate
rm .\Nimble.Modulith.slnNow you should have the following folders:
Nimble.Modulith.AppHost Nimble.Modulith.ServiceDefaults
and files:
Nimble.Modulith.slnx
Run the following commands from the same folder as your slnx file.
dotnet new webapi --name Nimble.Modulith.Web --output Nimble.Modulith.Web --use-minimal-apis --framework net10.0
dotnet sln add Nimble.Modulith.Web/Nimble.Modulith.Web.csproj --solution-folder "_Host"dotnet new classlib --name Nimble.Modulith.Users --output Nimble.Modulith.Users --framework net10.0dotnet sln add Nimble.Modulith.Users/Nimble.Modulith.Users.csproj --solution-folder "Users Module"dotnet new classlib --name Nimble.Modulith.Users.Contracts --output Nimble.Modulith.Users.Contracts --framework net10.0
dotnet sln add Nimble.Modulith.Users.Contracts/Nimble.Modulith.Users.Contracts.csproj --solution-folder "Users Module"dotnet sln listYou should see all 5 projects. If not you can use dotnet sln add <csproj path> to add any that are missing.
Move the Aspire projects to the _Host solution folder:
dotnet sln remove Nimble.Modulith.AppHost/Nimble.Modulith.AppHost.csproj
dotnet sln add Nimble.Modulith.AppHost/Nimble.Modulith.AppHost.csproj --solution-folder "_Host"
dotnet sln remove Nimble.Modulith.ServiceDefaults/Nimble.Modulith.ServiceDefaults.csproj
dotnet sln add Nimble.Modulith.ServiceDefaults/Nimble.Modulith.ServiceDefaults.csproj --solution-folder "_Host"This will change the default startup project. When you open in an IDE you'll need to set AppHost as the startup project manually.
We're going to have a lot of projects. We don't want to have different package versions all over the place. Run this from the folder with the slnx file. We're going to use this tool to help: CentralizedPackageConverter
dotnet tool install -g CentralisedPackageConverter
central-pkg-converter .The Aspire projects created by aspire new may target a different framework version. Use a central Directory.Build.props file to set the .NET version and remove the <TargetFramework>net9.0</TargetFramework> element from the two Aspire projects.
dotnet new buildpropsEdit the Directory.Build.props file so it looks like this:
<Project>
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>Remove these elements from AppHost and ServiceDefaults projects.
# Users project references Users.Contracts
dotnet add Nimble.Modulith.Users\Nimble.Modulith.Users.csproj reference Nimble.Modulith.Users.Contracts\Nimble.Modulith.Users.Contracts.csproj
# Web project references Users
dotnet add Nimble.Modulith.Web\Nimble.Modulith.Web.csproj reference Nimble.Modulith.Users\Nimble.Modulith.Users.csproj
# Web project references ServiceDefaults (if using Aspire)
dotnet add Nimble.Modulith.Web\Nimble.Modulith.Web.csproj reference Nimble.Modulith.ServiceDefaults\Nimble.Modulith.ServiceDefaults.csproj
# AspireHost references ServiceDefaults and Web
dotnet add Nimble.Modulith.AppHost\Nimble.Modulith.AppHost.csproj reference Nimble.Modulith.ServiceDefaults\Nimble.Modulith.ServiceDefaults.csproj
dotnet add Nimble.Modulith.AppHost\Nimble.Modulith.AppHost.csproj reference Nimble.Modulith.Web\Nimble.Modulith.Web.csprojYou may want to update the default namespaces in the Users projects:
- Update
Nimble.Modulith.Users\Class1.csto use namespaceNimble.Modulith.Users - Update
Nimble.Modulith.Users.Contracts\Class1.csto use namespaceNimble.Modulith.Users.Contracts
Or simply delete the generated Class1.cs files and create your own classes as needed.
Now we'll make sure we can see the Directory.Build.props and Directory.Packages.props files in our solution in VS2026 (or your IDE of choice). Open the Nimble.Modulith.slnx file and add this at the top:
<Folder Name="/__SolutionItems/">
<File Path="Directory.Build.props" />
<File Path="Directory.Packages.props" />
</Folder>The whole thing should look like this:
<Solution>
<Folder Name="/__SolutionItems/">
<File Path="Directory.Build.props" />
<File Path="Directory.Packages.props" />
</Folder>
<Folder Name="/Users Module/">
<Project Path="Nimble.Modulith.Users.Contracts/Nimble.Modulith.Users.Contracts.csproj" />
<Project Path="Nimble.Modulith.Users/Nimble.Modulith.Users.csproj" />
</Folder>
<Folder Name="/_Host/">
<Project Path="Nimble.Modulith.AppHost/Nimble.Modulith.AppHost.csproj" />
<Project Path="Nimble.Modulith.ServiceDefaults/Nimble.Modulith.ServiceDefaults.csproj" />
<Project Path="Nimble.Modulith.Web/Nimble.Modulith.Web.csproj" />
</Folder>
</Solution>At this point we have the basics: 2 Aspire projects, a eb host project, and 2 projects that represent our Users module. In the next lab we will configure Aspire to work with the web host and module and get user registration working.