Getting Started with FastEndpoints for Building Web APIs in .NET
A friendly beginner guide to FastEndpoints in .NET. Learn the REPR pattern, build your first endpoint, add validation, and see how it compares to controllers.
A restaurant where each dish has its own cook
Think about a small family restaurant. In some kitchens, one head cook tries to make every dish on the menu. When ten orders come at once, that one cook gets confused. The soup burns while they chop onions for the curry. Everything slows down, and mistakes happen.
Now picture a better kitchen. Here, each dish has its own cook. One cook only makes biryani. Another only makes dosa. A third only makes lassi. When an order comes in, it goes straight to the right cook, who knows exactly what to do. Nobody steps on anyone's toes. Adding a new dish is easy: you just hire one more cook for that dish. The kitchen stays calm even when it is busy.
In the world of web APIs, the "one cook for everything" kitchen is like a big controller class that handles many routes. The "one cook per dish" kitchen is what FastEndpoints gives you. Each endpoint, like "create a user" or "get an order", becomes its own small class with one clear job.
In this post we will set up FastEndpoints from scratch, write our first endpoint, add validation, and see how it stacks up against the older ways of building APIs. By the end you will be able to build a clean, fast API of your own.
What is FastEndpoints?
FastEndpoints is a free, open-source framework for building REST APIs in ASP.NET Core 8 and newer. It is not a replacement for ASP.NET Core. It sits neatly on top of it and uses the same routing, the same middleware, and the same dependency injection you already know.
Its main idea is the REPR pattern, which stands for Request, Endpoint, Response. Say that word out loud and it sounds like "reaper". The idea is simple:
- Request: a small class that describes what the client sends you.
- Endpoint: a class that holds the logic for exactly one route.
- Response: a small class that describes what you send back.
Each endpoint is its own class in its own file. That is the whole trick. Let us picture it.
This is different from the controller world, where one OrdersController might hold five or ten methods. With FastEndpoints, "create order" and "get order" are two separate classes. They never share code by accident, and they never grow into a giant tangled file.
Why pick FastEndpoints?
You might wonder why you would add a framework when ASP.NET Core already builds APIs. Here are the honest reasons.
| What you get | Why it helps a beginner |
|---|---|
| One class per endpoint | Easy to find code; no giant files to scroll |
| Almost no boilerplate | Less typing, fewer places to make mistakes |
| Built-in validation | Bad input is rejected before your logic runs |
| Automatic Swagger docs | A test page for your API with zero extra work |
| Speed close to Minimal APIs | Fast and light on memory |
| No paid dependencies needed | Its own command bus, so no need for paid MediatR |
That last point matters today. The popular libraries MediatR and MassTransit both moved to commercial paid licenses in 2025. FastEndpoints includes its own lightweight command bus and event system, so you can build clean apps without reaching for a paid tool.
Setting it up step by step
Let us build a tiny API together. First, create a new empty web project and add the FastEndpoints package.
dotnet new web -n MyFastApi
cd MyFastApi
dotnet add package FastEndpointsNow open Program.cs. We need to do just two things: register the services and turn on the endpoint middleware. Here is the full, working starting file.
using FastEndpoints;
var builder = WebApplication.CreateBuilder(args);
// 1. Register FastEndpoints services.
builder.Services.AddFastEndpoints();
var app = builder.Build();
// 2. Wire FastEndpoints into the request pipeline.
app.UseFastEndpoints();
app.Run();That is the entire setup. Notice there are no MapGet or MapPost lines here. FastEndpoints scans your project, finds every endpoint class by itself, and registers the routes for you. You never have to come back to Program.cs when you add a new endpoint. The file stays small forever.
From zero to a running FastEndpoints API
Steps
New project
dotnet new web
Add package
add FastEndpoints
Register and use
AddFastEndpoints + UseFastEndpoints
Run
endpoints auto-discovered
Your first endpoint
Let us make the classic "hello" endpoint. Create a new file called HelloEndpoint.cs. Because this endpoint takes no input from the client, we use EndpointWithoutRequest.
using FastEndpoints;
public class HelloEndpoint : EndpointWithoutRequest
{
public override void Configure()
{
Get("/hello");
AllowAnonymous(); // no login needed
}
public override async Task HandleAsync(CancellationToken ct)
{
await SendAsync(new { Message = "Hello from FastEndpoints!" });
}
}Two methods do all the work, and they read like plain English:
Configure()says what this endpoint is. Here it answersGET /helloand needs no login.HandleAsync()says what to do when a request arrives. Here it sends back a small message.
Run the app with dotnet run, open https://localhost:5001/hello in your browser, and you will see your JSON message. You just built a working API endpoint, and you never touched Program.cs.
Adding a request: create a user
A real API takes input. Let us build an endpoint that creates a user. With REPR, we make a small request class to describe the input, a small response class for the output, and one endpoint class that ties them together.
using FastEndpoints;
// Request: what the client sends.
public class CreateUserRequest
{
public string Name { get; set; } = string.Empty;
public int Age { get; set; }
}
// Response: what we send back.
public class CreateUserResponse
{
public string Message { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; }
}
// Endpoint: ties them together with one job.
public class CreateUserEndpoint : Endpoint<CreateUserRequest, CreateUserResponse>
{
public override void Configure()
{
Post("/users");
AllowAnonymous();
}
public override async Task HandleAsync(CreateUserRequest req, CancellationToken ct)
{
var response = new CreateUserResponse
{
Message = $"User {req.Name} was created.",
CreatedAt = DateTime.UtcNow
};
await SendAsync(response);
}
}Look at the class name: Endpoint<CreateUserRequest, CreateUserResponse>. You are telling FastEndpoints, in plain types, exactly what goes in and what comes out. FastEndpoints reads the JSON body of the POST request and fills your CreateUserRequest for you. This is called model binding, and you get it for free.
Here is the journey of a single request through the system.
Adding validation the easy way
Right now, someone could send an empty name or a silly age like minus five. We should stop bad input before it reaches our logic. FastEndpoints uses FluentValidation, a friendly library for writing rules. You write a validator class, and FastEndpoints runs it automatically.
using FastEndpoints;
using FluentValidation;
public class CreateUserValidator : Validator<CreateUserRequest>
{
public CreateUserValidator()
{
RuleFor(x => x.Name)
.NotEmpty().WithMessage("Name is required.")
.MinimumLength(2).WithMessage("Name is too short.");
RuleFor(x => x.Age)
.GreaterThan(0).WithMessage("Age must be more than 0.")
.LessThan(150).WithMessage("Age looks wrong.");
}
}You do not have to register this validator anywhere. FastEndpoints finds it, matches it to CreateUserRequest, and runs it before your HandleAsync ever starts. If the input breaks a rule, the client gets a clean 400 Bad Request with a helpful message, and your logic is never even called. Your handler stays focused on the happy path.
What happens to a bad request
Steps
Request arrives
client sends JSON
Bind to DTO
fill request object
Validate
run the rules
Decision
valid or 400
Handler
only good data runs
How it compares to the older ways
You have three main ways to build APIs in ASP.NET Core today: controllers, Minimal APIs, and FastEndpoints. None of them is wrong. They just suit different tastes. Here is an honest summary based on recent .NET 10 benchmarks and everyday use.
| Feature | Controllers (MVC) | Minimal APIs | FastEndpoints |
|---|---|---|---|
| Code structure | Many methods per class | Routes in one place | One class per endpoint |
| Boilerplate | High | Low | Very low |
| Speed | Slowest of the three | Fastest | Almost as fast as Minimal |
| Memory per request | Highest | Lowest | Very low |
| Built-in validation | Manual or attributes | Manual | Yes, via FluentValidation |
| Best for | Large legacy enterprise apps | Tiny services, serverless | Structured, growing APIs |
In benchmarks, controllers often allocate around 2.5 to 3 times more memory per request than FastEndpoints, because the MVC pipeline does extra work like action filters and content negotiation. Minimal APIs and FastEndpoints sit very close together, often within measurement noise. So with FastEndpoints you get the speed of Minimal APIs and the tidy structure that controllers were trying to give you, without the weight.
A few handy extras
Once you are comfortable, FastEndpoints has small touches that make daily work nicer.
- Route parameters are easy. Call
Get("/users/{id}")inConfigure(), and add a matchingint Idproperty to your request. FastEndpoints fills it from the URL. - Swagger docs come almost free. Add the
FastEndpoints.Swaggerpackage, callAddFastEndpoints().SwaggerDocument(), and you get an interactive test page for your whole API. - Sending different results is simple. Use
SendOkAsync,SendCreatedAtAsync, orSendNotFoundAsyncto return the right HTTP status without fuss. - Grouping and security let you tag endpoints, require roles, or apply policies, all inside that same readable
Configure()method.
You do not need any of these to start. They are just there when you grow.
A common beginner mistake to avoid
When you first try FastEndpoints, you might forget that the endpoint class must be public and must inherit from one of the base types like Endpoint<TRequest> or EndpointWithoutRequest. If an endpoint does not show up when you run the app, that is almost always the reason. The scanner only picks up public classes that inherit from the right base. Check that first, and you will save yourself some head-scratching.
Another small gotcha: keep your request and response classes simple. They are meant to be plain data holders. Do not put business logic inside them. Logic belongs in HandleAsync. This keeps the "Request" and "Response" parts of REPR clean and predictable.
Quick recap
- FastEndpoints is a free, open-source framework for ASP.NET Core 8 and newer that uses the REPR pattern: Request, Endpoint, Response.
- Each endpoint is its own small class with two main methods:
Configure()to describe the route, andHandleAsync()to do the work. - Setup is two lines:
AddFastEndpoints()andUseFastEndpoints(). Endpoints are auto-discovered, soProgram.csstays tiny. - Validation is built in through FluentValidation. Write a
Validator<T>class and it runs automatically before your logic. - It is fast and light, close to Minimal APIs and far lighter than controllers, while giving you a cleaner structure.
- It has its own command bus, so you do not need the now-paid MediatR.
- You can mix it with existing controllers and Minimal APIs, so it is safe to try on a small part of your app first.
References and further reading
- FastEndpoints official documentation — Get Started
- FastEndpoints — Validation guide
- FastEndpoints on GitHub
- FastEndpoints, Controllers, and Minimal APIs Compared — NimblePros Blog
- FastEndpoints vs Minimal API vs Controllers: .NET 10 Benchmarks — Code Majesty
- Getting Started with FastEndpoints — Anton Martyniuk
- Minimal APIs overview — Microsoft Learn
Related Posts
Automatically Register Minimal APIs in ASP.NET Core
Learn to auto-register Minimal API endpoints in ASP.NET Core using the IEndpoint pattern, assembly scanning, and source generators. With diagrams and code.
Best Practices for Building REST APIs in ASP.NET Core
A friendly, beginner guide to REST API best practices in ASP.NET Core with naming, status codes, validation, ProblemDetails, paging, versioning, security, and code.
Adding Validation to the Options Pattern in ASP.NET Core
Learn to validate the options pattern in ASP.NET Core using data annotations, IValidateOptions, ValidateOnStart, and source generation, with simple examples and diagrams.
Productive Web API Development with FastEndpoints and Vertical Slice Architecture in .NET
Learn how FastEndpoints and Vertical Slice Architecture work together to build clean, fast, and easy-to-grow web APIs in .NET 10, step by step.
Options Pattern Validation in ASP.NET Core With FluentValidation
Validate the options pattern in ASP.NET Core using FluentValidation, IValidateOptions, and ValidateOnStart. Simple steps, diagrams, and full code examples.
Top 15 Mistakes Developers Make When Creating Web APIs
A warm, beginner-friendly tour of the 15 most common Web API mistakes in ASP.NET Core, with simple fixes, diagrams, tables, and clear C# examples.