Pathum.ModularMonolith.Templates
1.0.1
dotnet new install Pathum.ModularMonolith.Templates@1.0.1
Pathum.ModularMonolith.Templates
Two dotnet new templates for ASP.NET Core (.NET 10) backends:
| Command | What it creates |
|---|---|
dotnet new modmonolith -n MyProject |
The whole solution: host, building blocks, tests, Docker |
dotnet new modmodule -n Students --projectName MyProject |
One business module: 6 projects, added to the solution |
The create-react-app experience, for a modular monolith backend.
๐ USAGE.md โ the full walkthrough: install โ project โ module โ a working
POST /api/students โ migrations โ cross-module events โ testing โ troubleshooting.
Quick start
Needs the .NET 10 SDK, and nothing else. Two minutes from nothing to a running API with a module in it.
# 1. install the templates - once per machine, no project required
dotnet new install Pathum.ModularMonolith.Templates
# 2. create the solution
dotnet new modmonolith -n EduFlow
cd EduFlow
# 3. run it - a fresh project has no DbContext yet, so it needs no database
dotnet run --project src/Host/EduFlow.Api # http://localhost:5080/scalar
# 4. add your first business module
cd src/Modules
dotnet new modmodule -n Students --projectName EduFlow
cd ../..
That leaves exactly one line to write, in src/Host/EduFlow.Api/Program.cs โ the generator prints it
for you when the module is created:
IModule[] modules =
[
new EduFlow.Students.StudentsModule(),
];
dotnet build && dotnet test
Two things worth knowing before you pick a name:
--projectNamemust match the-nyou gavemodmonolith. It is how the module knows what to call its namespaces.- Use a dot, never a hyphen โ
-n Edu.Flow, not-n Edu-Flow. See Use below for why.
Databases, migrations and Docker: Run it.
Install
dotnet new install Pathum.ModularMonolith.Templates
Check it, update it, remove it:
dotnet new list modmonolith # confirm
dotnet new install Pathum.ModularMonolith.Templates --force # update to the latest
dotnet new uninstall Pathum.ModularMonolith.Templates # remove
dotnet new uninstall # list everything installed
Not using nuget.org? Every release attaches the .nupkg, and it installs the same way:
dotnet new install ./Pathum.ModularMonolith.Templates.1.0.0.nupkg
Or straight from a clone โ see Changing the templates.
Use
Add as many modules as the business has capabilities โ Identity, Billing, Enrollment. Never
technical buckets like Services or Common:
cd src/Modules
dotnet new modmodule -n Identity --projectName EduFlow
dotnet new modmodule -n Payments --projectName EduFlow
-n renames every project, namespace, file and the solution. --projectName tells the module
template which solution it is being generated into.
Use a dot, not a hyphen. C# identifiers cannot contain -, so a hyphen is removed from every
project, assembly and namespace โ the folder keeps it, the run path does not:
-n |
Folder | Run with |
|---|---|---|
EduFlow-Server |
EduFlow-Server/ |
dotnet run --project src/Host/EduFlowServer.Api |
EduFlow.Server โ
|
EduFlow.Server/ |
dotnet run --project src/Host/EduFlow.Server.Api |
Same for spaces and @. If you already used a hyphen, dotnet run --project src/Host/*.Api runs it
whatever the name became, and the generated README.md has the real path filled in.
No scripts run and no --allow-scripts is needed: the module template adds its six projects to the
solution through dotnet new's built-in post action, and the host references src/Modules/* by glob,
so the only manual step is one line in Program.cs โ printed for you when the module is created.
Run it
A freshly generated project needs no database at all โ before the first module there is no
DbContext, so /health/ready is 200 with nothing installed. Once you add a module, pick one:
Without Docker โ you own the database:
# connection string is already in appsettings.json, pointing at localhost
dotnet run --project src/Host/EduFlow.Api # http://localhost:5080
With Docker โ compose runs the API and the database:
cp .env.example .env
docker compose up --build # http://localhost:8080
Both โ database in Docker, API on your machine. The everyday loop, and the credentials are generated to match, so it needs no configuration:
cp .env.example .env
docker compose up -d db
dotnet run --project src/Host/EduFlow.Api # http://localhost:5080
| Without Docker | With Docker | |
|---|---|---|
| API port | 5080 |
8080 |
| Connection string from | appsettings.json, user secrets, or Database__ConnectionString |
compose.yaml |
.env |
not read at all | read by compose |
Migrations never run on their own in either mode โ Database.Migrate() is not called anywhere, on
purpose. You run dotnet ef database update yourself.
USAGE.md ยง4 has
all of it in full.
Options
dotnet new modmonolith -n Shop --database sqlserver --auth jwt --openapiUi scalar --sampleModule true
| Option | Values | Default | What it changes |
|---|---|---|---|
--database |
postgres, sqlserver |
postgres |
EF provider, connection strings, the compose database service. Pass the same value to modmodule. |
--auth |
none, jwt |
none |
With jwt: registers JWT bearer against an OIDC authority and enables UseAuthentication/UseAuthorization. |
--openapiUi |
scalar, swagger, none |
scalar |
UI over the OpenAPI document, in Development. The document itself is always served at /openapi/v1.json. |
--docker |
true, false |
true |
Drops Dockerfile, compose.yaml, .dockerignore and .env.example when false. |
--sampleModule |
true, false |
false |
Adds a worked Students module โ entity, command, query, endpoints, EF configuration, contracts โ to read and then delete. |
modmodule takes --database too, and it must match the solution.
What you get
EduFlow/
โโโ EduFlow.slnx
โโโ global.json SDK pinned, rolls forward within .NET 10
โโโ Directory.Build.props TFM, nullable, analyzers - once, for every project
โโโ Directory.Packages.props Central package management: one version list
โโโ Dockerfile, compose.yaml One image, one Postgres
โโโ src/
โ โโโ Host/EduFlow.Api Composition root, options, middleware, health, OpenAPI
โ โโโ BuildingBlocks/
โ โ โโโ EduFlow.SharedKernel Entity, AggregateRoot, ValueObject, Result, Error
โ โ โโโ EduFlow.Application.Abstractions ICommand/IQuery + handlers, ICurrentUser,
โ โ โ IDateTimeProvider, IEventBus, IIntegrationEvent
โ โ โโโ EduFlow.Infrastructure Clock, current user, in-memory event bus
โ โ โโโ EduFlow.Presentation IEndpoint, IModule, GlobalExceptionHandler, ApiResults
โ โโโ Modules/ Empty. Modules are created, never assumed.
โโโ tests/
โโโ EduFlow.ArchitectureTests Boundary rules, enforced
โโโ EduFlow.UnitTests
โโโ EduFlow.IntegrationTests
โโโ EduFlow.ApiTests Boots the real host in memory
Each module the second template creates:
src/Modules/Students/
โโโ EduFlow.Students/ Composition root (StudentsModule : IModule)
โโโ EduFlow.Students.Contracts/ The only project other modules may reference
โโโ EduFlow.Students.Domain/ Plain C#. No EF Core, no ASP.NET.
โโโ EduFlow.Students.Application/ Vertical slices under Features/
โโโ EduFlow.Students.Infrastructure/ StudentsDbContext, schema "students", migrations
โโโ EduFlow.Students.Presentation/ Minimal API endpoints under /api/students
Design decisions
- One host, one image, many modules. Modules are folders of projects, not services.
- Clean architecture per module, vertical slices inside Application. No
StudentService.csgrowing to 2000 lines. - A DbContext and a schema per module, one physical database. The boundary is real before it is distributed.
- Cross-module access only through
Module.Contractsโ synchronously through an interface, or asynchronously through an integration event. The architecture tests fail the build otherwise. Result/Errorover exceptions for expected failures; oneGlobalExceptionHandlerfor the rest.- No mediator library, no generic repository, no outbox, no Redis, no RabbitMQ in the starter. Handlers are resolved from DI directly. Everything else is added when a project actually needs it โ the README of a generated project says where each one goes.
Notes
- Requires the .NET 10 SDK.
- Generated solutions use the
.slnxsolution format (the .NET 10 default). - The template source under
templates/modmonolithis itself a working solution:dotnet buildanddotnet testit directly while making changes, then reinstall.
Changing the templates
Edit under templates/, then:
dotnet new uninstall ./templates/modmonolith && dotnet new install ./templates/modmonolith
Verify before publishing โ a template is not finished until a freshly generated project builds:
cd /tmp && rm -rf TemplateTest && mkdir TemplateTest && cd TemplateTest
dotnet new modmonolith -n TestApp && cd TestApp && dotnet build && dotnet test
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.