ScriptsHub Technologies Global

.NET Minimal APIs: Ship Microservices Faster

Quick Summary-

A payments and billing platform in financial services had stalled halfway through a microservice programme. Every new service carried roughly 800 lines of bootstrap code before doing anything useful, and the team took about nine working days to ship one. We rebuilt five services on .NET Minimal APIs targeting .NET 10, cut per-service boilerplate by around 65%, and brought median delivery to four days. With .NET 8 and .NET 9 both leaving support on 10 November 2026, most teams are opening these services anyway. This case study covers the framework decision, the .NET 10 code and the seven-step playbook. Gains vary with service count and how much MVC you carry.

A team spending more time wiring controllers, filters and model binders than writing business logic is exactly the problem .NET Minimal APIs were designed to solve, eliminating unnecessary ceremony between a route and its handler. That was the case at a billing platform in financial services whose microservices programme had slipped two quarters.

The migration is happening regardless: .NET 8 and .NET 9 both leave support on 10 November 2026. The question is what you change while you are in there.

Why Were ASP.NET Core Microservices Taking Nine Days to Ship?

Because roughly 800 lines of bootstrap code came before the first business rule. The architecture was sound and the team capable, but each new service took about nine working days from ticket to production, most of it scaffolding.

The bootstrap was controller classes, attribute routing, model binders, a hand-written DI wire-up, filter registrations and OpenAPI annotations, with reviewers paging across seven files. The brief: no rewrite of the monolith, prove an approach on two services in four weeks, leave a playbook.

What Are ASP.NET Core Minimal APIs, and Why Did They Fit?

.NET Minimal APIs are a low-ceremony way to build HTTP endpoints, introduced in .NET 6 and matured through .NET 10: route handlers register directly against the request pipeline instead of being discovered on controller classes. Microsoft recommends ASP.NET Core Minimal APIs as the default for new projects, and that profile (JSON in, JSON out, small surface) is the microservice profile.

As a rule of thumb: minimal APIs when a service returns JSON and nothing else, controllers when you need custom model binders, Razor views or dozens of resources under one convention.

Published benchmarks put minimal APIs modestly ahead on requests per second for simple endpoints, though that gap closes once an endpoint is I/O-bound. Most of the saving is at startup and in developer time.

Of the 800 lines, roughly 430 were ceremony rather than behaviour: attribute routing, constructor injection plumbing, Swagger annotations and binding conventions. The model collapses most of that into inline route definitions and first-party OpenAPI generation.

Calling AddControllers() also registers the MVC stack (model binders, filters, formatter mapping, API Explorer) for services that only return JSON, and it is the first thing we strip in Microsoft technology services modernisation work. Microsoft’s Native AOT compatibility guidance lists minimal APIs as partially supported and MVC as not supported.

They earn that partial support through the Request Delegate Generator, which rewrites MapGet and its siblings into trim-friendly code the linker can analyse. Microsoft’s .NET Native AOT benchmark publishes such an app at roughly 9 MB. Several widely-cited write-ups quote figures under 5 MB. The benchmarks do not support them.

How Do You Build REST APIs with .NET Minimal APIs?

You can build REST APIs with .NET in three lines: no class, no attribute, no base type.

.NET Minimal API hello world example using WebApplication and MapGet to create a GET endpoint in Program.cs.

Every verb has a matching extension, and a handler can be an inline lambda or a named method reference. The second keeps Program.cs readable.

Binding is inferred, in a fixed order: explicit [From*] attributes, then well-known types such as HttpContext, then any type exposing BindAsync, then strings and TryParse types (route when the name matches a segment, query otherwise), then DI-registered services, and finally the request body as JSON.

Why .NET 10 Minimal APIs Over Controllers and FastEndpoints?

Because it cut boilerplate hardest while adding no third-party dependency. Three options went into the architecture review.

Only the minimal API path

 was piloted, so the FastEndpoints row is an estimate. Minimal APIs won on boilerplate, startup, and adding no dependency; every external package here triggers a security review that adds weeks.

We targeted [[FILL-1: exact SDK, e.g. 10.0.100]] throughout. The runtime was decided for us, because .NET 8 and .NET 9 both reach end of support on 10 November 2026, while .NET 10 runs to November 2028 under the .NET release and support policy.

How Does OpenAPI in ASP.NET Core Fit a Production Service?

OpenAPI in ASP.NET Core has been first-party since .NET 9 and emits OpenAPI 3.1 by default on .NET 10. The document generates itself once AddOpenApi() is registered. We rebuilt the smallest of the five, an invoice-lookup API, as the reference: 78 lines against 600.

why this works: WebApplication.CreateBuilder registers only routing, configuration, logging and dependency injection – no MVC stack, no action invoker, no assembly scan for controller types. Declaring the return type as Results<Ok<Invoice>, NotFound> lets TypedResults push accurate schemas into the generated document, so downstream consumers needed no client regeneration.

Validation is the piece teams most often get wrong. On .NET 10, AddValidation() checks data annotations on bound parameters and returns ProblemDetails without handler code, provided the interceptor property below is set.

We found that out the hard way. [[FILL-4: how the missing InterceptorsNamespaces property showed up – what was the symptom (invalid payloads returning 200/201? a test that passed locally and failed in QA?), who spotted it, and roughly how long it went unnoticed. Two or three sentences of what actually happened, in Siddharth’s words.]]

Built-in validation covers attribute-expressible rules. Cross-field logic and database lookups belong in FluentValidation, as a minimal API endpoint filter on the route group.

If your team is spending more time on bootstrap than billing logic, that is a fixable, four-week problem. See what a fixed-scope .NET pilot covers →

How Did We Validate Minimal APIs Performance?

Performance claims are easy to assert and hard to defend, so we ran three checks.

We benchmarked time to readiness across 200 container starts on the client’s own AKS cluster, not a workstation: [[FILL-2: node pool SKU and count, e.g. 3x Standard_D4s_v5]], image pre-pulled on every node so layer download stayed out of the measurement. The median came in at roughly 6.8 seconds against 12.1 for the controller baseline. The runtime upgrade and the leaner startup path delivered that together; the framework change alone did not.

We load-tested with [[FILL-3: tool and version, e.g. k6 v0.5x]] at 500 requests per second, holding p99 latency under 45 ms with no 5xx.

Finally we diffed the generated OpenAPI document against the controller-era contract, the check teams skip.

What Did Minimal APIs Deliver for These Microservices?

We changed only the endpoint layer. Figures are from this engagement.

[[FILL-5: two-line client quote if sign-off allows, attributed by role only, e.g. “Head of Platform Engineering, UK payments provider”. Omit this line entirely if no quote is approved.]]

Boilerplate fell 65% but time-to-ship fell 55%, which looks odd until you sit in a review. A reviewer who can hold a whole service in their head asks fewer questions, and the review round-trip is where most of those nine days went.

We see the same on monolith to microservices migrations: the delivery gain is what the business notices first.

How Can Your Team Adopt .NET Minimal APIs?

Run a four-week pilot in seven steps, then reuse the playbook:

  1. Upgrade the runtime first. Target net10.0 before any framework work; a runtime losing support in November means paying twice.
  2. Pick a low-risk pilot. Well-understood contracts, moderate traffic, behind a feature flag so a regression costs a toggle.
  3. Mirror the existing OpenAPI contract. Diff the regenerated document against the old one so downstream clients need no changes.
  4. Settle the validation pattern early. Decide once whether a rule belongs in data annotations or a shared endpoint filter; inconsistency here is the commonest source of drift.
  5. Move routes out of Program.cs early. Put each feature’s endpoints in an Endpoints folder behind a static extension method, the convention our ASP.NET Core microservices development teams standardise on first.

RequireAuthorization on the group applies the policy to every route inside it, so JWT rules are declared once. A reflection-based pattern scales further; our Minimal API vs Controller comparison covers it.

  1. Benchmark on the target platform. Capture boilerplate and startup numbers on the same cluster, across a sample large enough to survive cache variance.
  2. Write the playbook while it is fresh. A guide covering project structure, route-group conventions, validation and error handling makes services two through five cheap, and it is what our DevOps engineers hand back.

Should Native AOT Readiness Decide Your Default?

For greenfield work, yes, with one caveat: we did not publish AOT here, because EF Core rules it out for these services. We treated AOT readiness as optionality, not a plan. Controllers still fit large APIs with custom model binders or Razor views, and a pre-.NET 6 estate is a legacy application modernisation question rather than a framework one. Both models run in one application, so adoption can be incremental.

Most teams can write the endpoints. What takes four weeks is knowing what to measure, measuring it on your cluster rather than a laptop, and diffing the contract before downstream teams find the drift. That is the part we do.

.NET 8 and .NET 9 leave support on 10 November 2026, so you are touching these services anyway. ScriptsHub Technologies runs four-week minimal API pilots on two of them, proving the gains on your platform and handing back the playbook. Talk to our .NET team →

Frequently Asked Questions

Q. What are .NET Minimal APIs?

A low-ceremony way to build HTTP endpoints by registering route handlers directly against the request pipeline, rather than declaring controller classes.

Q. How does parameter binding work in ASP.NET Core Minimal APIs?

By inference: explicit [From*] attributes first, then well-known types, BindAsync, TryParse types from route or query, DI services, then the request body as JSON.

Q. Does Native AOT publishing work with minimal APIs?

Yes, unlike MVC. The Request Delegate Generator rewrites route registration into trim-friendly code, and Microsoft’s benchmark publishes such an app at roughly 9 MB, not the sub-5 MB figure often repeated. EF Core is not AOT-compatible.

Q. How do .NET 10 Minimal APIs handle validation?

AddValidation() applies data-annotation checks to bound parameters and returns ProblemDetails automatically. FluentValidation behind an endpoint filter covers cross-field rules and data lookups.

Q. How does OpenAPI in ASP.NET Core work with minimal APIs?

Natively, and since .NET 9. The built-in Microsoft.AspNetCore.OpenApi package generates the document once AddOpenApi() is registered; MapOpenApi() serves it, and TypedResults supplies the schemas.

Q. Should I migrate existing controllers to minimal APIs?

Only when you are already touching the service, or startup cost is a hard constraint. Both models run side by side, so new endpoints can be minimal APIs.

Exit mobile version