Pathum.ModularMonolith.Templates 1.0.1

dotnet new install Pathum.ModularMonolith.Templates@1.0.1
                    
This package contains a .NET Template Package you can call from the shell/command line.

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:

  • --projectName must match the -n you gave modmonolith. 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.cs growing 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/Error over exceptions for expected failures; one GlobalExceptionHandler for 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 .slnx solution format (the .NET 10 default).
  • The template source under templates/modmonolith is itself a working solution: dotnet build and dotnet test it 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.

Version Downloads Last Updated
1.0.1 143 8/11/2026
1.0.0 131 8/11/2026