Skip to main content

Minimal APIs in .NET 8: Build Fast APIs (2026 Tutorial)

Learn how to build lightweight Minimal APIs in .NET 8 with C#. Step-by-step tutorial, code examples, and best practices. Start building fast APIs today!

If you want to build lightweight APIs fast, Minimal APIs in .NET 8 are the fastest way to ship a production-ready HTTP endpoint with the least amount of boilerplate. Introduced in .NET 6 and dramatically improved through .NET 8, Minimal APIs let you create a fully functional REST API in just a handful of lines of C# code—no controllers, no attributes, and no ceremony. In this tutorial, you'll learn exactly how to create a Minimal API in .NET 8, wire up dependency injection, return JSON, validate input, and follow the best practices that separate hobby projects from production-grade services.

Whether you're a beginner searching for a Minimal API tutorial, an intermediate developer looking for best practices, or a senior engineer evaluating performance trade-offs, this guide covers it all with runnable examples.

What Are Minimal APIs in .NET 8?

Minimal APIs are a streamlined approach to building HTTP APIs in ASP.NET Core. Instead of the traditional MVC pattern with controllers, base classes, and routing attributes, you define endpoints directly on the WebApplication instance. The result is less code, faster startup, and a smaller memory footprint—ideal for microservices, serverless functions, and high-throughput services.

Why use Minimal APIs? The key benefits are:

  • Less boilerplate — A working endpoint takes 4–5 lines, not a whole class.
  • Better performance — Reduced overhead compared to the full MVC pipeline.
  • Faster onboarding — New developers read the entire API in one file.
  • Cloud-native fit — Perfect for containers and microservices where startup time matters.

How to Create a Minimal API in .NET 8

Let's start with the classic "Hello World". Make sure you have the .NET 8 SDK installed, then create a new project:

dotnet new web -n MinimalApiDemo
cd MinimalApiDemo
dotnet run

Open Program.cs and you'll see the entire application—there's no Startup.cs file thanks to top-level statements. Here's the minimal setup:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello from Minimal APIs in .NET 8!");

app.Run();

That's a complete, running web server. The MapGet method maps an HTTP GET request to a handler. The handler is just a lambda—.NET handles serialization, routing, and the response automatically.

Building a REST API in C# with CRUD Endpoints

A real API needs more than a greeting. Let's build a small Todo service that demonstrates all the HTTP verbs. This is the core of building a REST API in C# with Minimal APIs.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

var todos = new List<Todo>();

// GET all todos
app.MapGet("/todos", () => todos);

// GET a single todo by id
app.MapGet("/todos/{id}", (int id) =>
{
    var todo = todos.FirstOrDefault(t => t.Id == id);
    return todo is not null ? Results.Ok(todo) : Results.NotFound();
});

// POST a new todo
app.MapPost("/todos", (Todo todo) =>
{
    todos.Add(todo);
    return Results.Created($"/todos/{todo.Id}", todo);
});

// PUT to update an existing todo
app.MapPut("/todos/{id}", (int id, Todo input) =>
{
    var todo = todos.FirstOrDefault(t => t.Id == id);
    if (todo is null) return Results.NotFound();

    todo.Title = input.Title;
    todo.IsComplete = input.IsComplete;
    return Results.NoContent();
});

// DELETE a todo
app.MapDelete("/todos/{id}", (int id) =>
{
    var todo = todos.FirstOrDefault(t => t.Id == id);
    if (todo is null) return Results.NotFound();

    todos.Remove(todo);
    return Results.NoContent();
});

app.Run();

record Todo
{
    public int Id { get; set; }
    public string? Title { get; set; }
    public bool IsComplete { get; set; }
}

Notice how the Results class gives you typed HTTP responses—Results.Ok(), Results.NotFound(), Results.Created(), and Results.NoContent()—so you control status codes precisely without extra plumbing. .NET 8 also introduced TypedResults, which is strongly typed and improves testability and OpenAPI documentation:

app.MapGet("/todos/{id}", Results<Ok<Todo>, NotFound> (int id) =>
{
    var todo = todos.FirstOrDefault(t => t.Id == id);
    return todo is not null
        ? TypedResults.Ok(todo)
        : TypedResults.NotFound();
});

Dependency Injection in Minimal APIs

One reason Minimal APIs scale to real projects is first-class dependency injection. You register services on the builder and inject them directly into endpoint handlers as parameters—ASP.NET Core resolves them automatically.

var builder = WebApplication.CreateBuilder(args);

// Register a service
builder.Services.AddSingleton<ITodoService, TodoService>();

var app = builder.Build();

// Inject ITodoService into the handler
app.MapGet("/todos", (ITodoService service) => service.GetAll());

app.Run();

interface ITodoService
{
    IEnumerable<Todo> GetAll();
}

class TodoService : ITodoService
{
    private readonly List<Todo> _todos = new();
    public IEnumerable<Todo> GetAll() => _todos;
}

Why this matters: The framework distinguishes between route parameters, query strings, the request body, and injected services based on their type and source. This keeps your handlers clean and fully testable without coupling them to HTTP details.

Organizing Endpoints with Route Groups

A common pitfall with Minimal APIs is dumping every endpoint into one giant Program.cs. .NET 8 solves this with route groups via MapGroup, letting you apply a shared prefix, filters, and metadata to related endpoints.

var todosApi = app.MapGroup("/todos")
                  .WithTags("Todos");

todosApi.MapGet("/", (ITodoService service) => service.GetAll());
todosApi.MapGet("/{id}", (int id, ITodoService service) => service.GetById(id));
todosApi.MapPost("/", (Todo todo, ITodoService service) => service.Add(todo));

For larger projects, move groups into extension methods (e.g. app.MapTodoEndpoints()) in separate files. This keeps each feature self-contained and maintains readability as your API grows.

Validation and Error Handling Best Practices

Minimal APIs don't include automatic model validation out of the box like MVC controllers do, so this is a frequent source of bugs. The cleanest approach in .NET 8 is to use endpoint filters, which run before your handler executes.

app.MapPost("/todos", (Todo todo) =>
{
    todos.Add(todo);
    return Results.Created($"/todos/{todo.Id}", todo);
})
.AddEndpointFilter(async (context, next) =>
{
    var todo = context.GetArgument<Todo>(0);
    if (string.IsNullOrWhiteSpace(todo.Title))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            { "Title", new[] { "Title is required." } }
        });
    }
    return await next(context);
});

Endpoint filters are reusable and composable, making them ideal for cross-cutting concerns like validation, logging, and authentication checks.

Adding OpenAPI and Swagger Documentation

Documentation is essential for any public-facing API. With .NET 8, enabling Swagger UI takes just a few lines, and route groups plus TypedResults produce rich, accurate schemas automatically.

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

Minimal APIs vs Controllers: When to Use Each

A question that comes up constantly: should you use Minimal APIs or traditional controllers? Here's the practical guidance:

  • Choose Minimal APIs for microservices, serverless endpoints, lightweight back-ends, prototypes, and any service where startup time and simplicity are priorities.
  • Choose controllers for large enterprise applications with complex conventions, heavy use of model binding, action filters, and teams already standardized on MVC patterns.

The good news: both run on the same ASP.NET Core runtime, deliver comparable performance for most workloads, and can coexist in the same project. You're not locked in.

Common Pitfalls to Avoid

  • Putting all logic in Program.cs — Use route groups and extension methods to stay organized.
  • Forgetting validation — Minimal APIs won't validate models for you; add endpoint filters.
  • Ignoring async — For database or network calls, use async handlers and return Task<IResult> to avoid blocking threads.
  • Returning raw exceptions — Use app.UseExceptionHandler() and the Problem Details standard for consistent error responses.
  • Skipping TypedResults — They improve testability and produce better OpenAPI docs than untyped Results.

Conclusion: Key Takeaways

Minimal APIs in .NET 8 are the modern, recommended way to build lightweight APIs fast in C#. They strip away boilerplate while retaining the full power of ASP.NET Core—dependency injection, middleware, authentication, and OpenAPI support all work seamlessly. For microservices and cloud-native applications, they're often the best default choice.

Here's what to remember:

  • Define endpoints directly with MapGet, MapPost, MapPut, and MapDelete.
  • Use TypedResults for strongly-typed, testable, well-documented responses.
  • Inject services directly into handlers via dependency injection.
  • Organize at scale with MapGroup and extension methods.
  • Add validation with endpoint filters and handle errors with Problem Details.

Now you have everything you need to build a production-ready REST API in C# using Minimal APIs in .NET 8. Spin up a new project, copy the examples above, and ship your first lightweight API today. Happy coding!

About csharp-coder.com
Your go-to resource for C#, .NET, and modern software development. Follow along for daily tutorials, tips, and real-world examples.

Comments

Popular posts from this blog

Angular 14 CRUD Operation with Web API .Net 6.0

How to Perform CRUD Operation Using Angular 14 In this article, we will learn the angular crud (create, read, update, delete) tutorial with ASP.NET Core 6 web API. We will use the SQL Server database and responsive user interface for our Web app, we will use the Bootstrap 5. Let's start step by step. Step 1 - Create Database and Web API First we need to create Employee database in SQL Server and web API to communicate with database. so you can use my previous article CRUD operations in web API using net 6.0 to create web API step by step. As you can see, after creating all the required API and database, our API creation part is completed. Now we have to do the angular part like installing angular CLI, creating angular 14 project, command for building and running angular application...etc. Step 2 - Install Angular CLI Now we have to install angular CLI into our system. If you have already installed angular CLI into your system then skip this step.  To install angular CLI ope...

Angular 14 : 404 error during refresh page after deployment

In this article, We will learn how to solve 404 file or directory not found angular error in production.  Refresh browser angular 404 file or directory not found error You have built an Angular app and created a production build with ng build --prod You deploy it to a production server. Everything works fine until you refresh the page. The app throws The requested URL was not found on this server message (Status code 404 not found). It appears that angular routing not working on the production server when you refresh the page. The error appears on the following scenarios When you type the URL directly in the address bar. When you refresh the page The error appears on all the pages except the root page.   Reason for the requested URL was not found on this server error In a Multi-page web application, every time the application needs to display a page it has to send a request to the web server. You can do that by either typing the URL in the address bar, clicking on the Me...

Send an Email via SMTP with MailKit Using .NET 6

How to Send an Email in .NET Core This tutorial show you how to send an email in .NET 6.0 using the MailKit email client library. Install MailKit via NuGet Visual Studio Package Manager Console: Install-Package MailKit How to Send an HTML Email in .NET 6.0 This code sends a simple HTML email using the Gmail SMTP service. There are instructions further below on how to use a few other popular SMTP providers - Gmail, Hotmail, Office 365. // create email message var email = new MimeMessage(); email.From.Add(MailboxAddress.Parse("from_address@example.com")); email.To.Add(MailboxAddress.Parse("to_address@example.com")); email.Subject = "Email Subject"; email.Body = new TextPart(TextFormat.Html) { Text = "<h1>Test HTML Message Body</h1>" }; // send email using var smtp = new SmtpClient(); smtp.Connect("smtp.gmail.com", 587, SecureSocketOptions.StartTls); smtp.Authenticate("[Username]", "[Password]"); smtp.Se...