# How ASP.NET Core Handles Routing: From IRouter to Endpoint Routing

> Understand how ASP.NET Core routing evolved from IRouter to Endpoint Routing. Discover how this system efficiently matches HTTP requests to your application's endpoints.

- Repository: [.NET Platform/aspnetcore](https://github.com/dotnet/aspnetcore)
- Tags: internals
- Published: 2026-07-13

---

**ASP.NET Core routing matches HTTP requests to endpoints through a middleware pipeline that evolved from the legacy IRouter model to the modern endpoint routing system introduced in version 3.0.**

The routing system in the [dotnet/aspnetcore](https://github.com/dotnet/aspnetcore) repository directs incoming HTTP requests to appropriate handlers using a sophisticated middleware architecture. Understanding how ASP.NET Core routing works internally reveals why the framework maintains two distinct models and how the current endpoint routing system achieves higher performance.

## Classic Routing vs. Endpoint Routing

The framework supports two routing architectures that coexist for backward compatibility. The modern endpoint routing system is recommended for new applications, while the legacy IRouter-based system remains available for older codebases.

### Legacy IRouter-Based Routing

The original routing model relies on the `IRouter` interface and the `RouterMiddleware`. When you call `UseRouter` in [`src/Http/Routing/src/Builder/RoutingBuilderExtensions.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Routing/src/Builder/RoutingBuilderExtensions.cs) (lines 20-35), the middleware pipeline adds `RouterMiddleware` to the request chain.

`RouterMiddleware.Invoke` (found in [`src/Http/Routing/src/RouterMiddleware.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Routing/src/RouterMiddleware.cs) lines 40-53) creates a `RouteContext`, sets the provided `IRouter`, and invokes `IRouter.RouteAsync`. If the router finds no matching handler, the request flows to the next middleware in the pipeline.

### Modern Endpoint Routing (ASP.NET Core 3.0+)

The current architecture uses `UseRouting()` and `UseEndpoints()` extension methods defined in [`src/Http/Routing/src/Builder/EndpointRoutingApplicationBuilderExtensions.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Routing/src/Builder/EndpointRoutingApplicationBuilderExtensions.cs). This model separates route matching from endpoint execution, enabling middleware to inspect the selected endpoint before the final handler runs.

## The Endpoint Routing Pipeline

Modern ASP.NET Core routing operates in two distinct phases: matching and execution.

### Matching Requests with EndpointRoutingMiddleware

The `EndpointRoutingMiddleware` (implemented in [`src/Http/Routing/src/EndpointRoutingMiddleware.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Routing/src/EndpointRoutingMiddleware.cs)) handles the matching phase. When `Invoke` executes (lines 99-124), it checks whether an endpoint has already been set on the `HttpContext`. If not, it asynchronously matches the request against a composite `EndpointDataSource` containing all registered endpoints.

The middleware uses a `Matcher` created by `MatcherFactory` to evaluate the request against the endpoint collection. When a match is found, the selected endpoint is stored via `HttpContext.SetEndpoint`, and the request proceeds to subsequent middleware.

The `SetRoutingAndContinue` method (lines 140-176) handles the transition between matching and execution, including short-circuiting logic for scenarios like request size limits or diagnostic endpoints.

### Executing Endpoints with EndpointMiddleware

The `UseEndpoints` method adds `EndpointMiddleware` to the pipeline. This middleware executes the delegate attached to the matched endpoint stored in `HttpContext`. Because the matching already occurred in `EndpointRoutingMiddleware`, this phase focuses solely on running the endpoint logic with any associated metadata (authorization, CORS, etc.).

## Core Routing Components

Several key abstractions power the routing system:

**IEndpointRouteBuilder** – collects `Endpoint` objects through methods like `MapGet`, `MapPost`, and `MapControllerRoute` (defined in [`src/Http/Routing/src/Builder/EndpointRouteBuilderExtensions.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Routing/src/Builder/EndpointRouteBuilderExtensions.cs)). These methods create `RouteEndpoint` instances that combine URL patterns with request delegates.

**Endpoint** – represents a compiled routing target containing the request delegate, routing metadata, and additional metadata such as authorization policies or CORS requirements. The `RouteEndpoint` class in [`src/Http/Routing/src/RouteEndpoint.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Routing/src/RouteEndpoint.cs) provides the concrete implementation.

**Matcher** – a compiled, high-performance data structure that evaluates HTTP requests against the endpoint collection. The framework builds this matcher from the composite `EndpointDataSource` (defined in [`src/Http/Routing/src/EndpointDataSource.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Routing/src/EndpointDataSource.cs)) during application startup.

**RouteOptions** – configures routing behavior including URL case sensitivity, trailing slash handling, and fallback routes via the options pattern.

## Implementation Examples

The following examples demonstrate both routing approaches:

```csharp
// Classic routing (IRouter) – rarely needed today
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseRouter(new RouteBuilder(app)
{
    // Configure routes manually
    routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    }
});

```

```csharp
// Modern endpoint routing (recommended)
var app = WebApplication.CreateBuilder(args).Build();

app.UseRouting();               // Adds EndpointRoutingMiddleware

app.UseEndpoints(endpoints =>
{
    // Minimal API endpoint
    endpoints.MapGet("/", () => "Hello, world!");

    // MVC controller endpoints
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});

app.Run();

```

## Summary

- **ASP.NET Core routing** uses a middleware pipeline that matches requests to endpoints before executing them.
- **Two models coexist**: the legacy `IRouter` system (via `UseRouter`) and the modern endpoint routing system (via `UseRouting`/`UseEndpoints`).
- **Endpoint routing** separates matching (handled by `EndpointRoutingMiddleware` in [`src/Http/Routing/src/EndpointRoutingMiddleware.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Routing/src/EndpointRoutingMiddleware.cs)) from execution (handled by `EndpointMiddleware`).
- **Key classes** include `IEndpointRouteBuilder` for collecting endpoints, `Matcher` for high-performance request evaluation, and `RouteEndpoint` for representing compiled routing targets.
- **Performance benefits** arise from the compiled `Matcher` data structure and the ability to inspect endpoints earlier in the middleware pipeline.

## Frequently Asked Questions

### What is the difference between UseRouter and UseRouting?

`UseRouter` (from [`RoutingBuilderExtensions.cs`](https://github.com/dotnet/aspnetcore/blob/main/RoutingBuilderExtensions.cs)) enables the classic IRouter-based routing where a single router object handles the entire matching process. `UseRouting` (from [`EndpointRoutingApplicationBuilderExtensions.cs`](https://github.com/dotnet/aspnetcore/blob/main/EndpointRoutingApplicationBuilderExtensions.cs)) adds the modern `EndpointRoutingMiddleware` that uses a compiled `Matcher` against a composite data source, supporting endpoint inspection by earlier middleware.

### How does endpoint routing improve performance?

Endpoint routing builds a compiled `Matcher` data structure from the `EndpointDataSource` during startup rather than evaluating routes sequentially at runtime. This structure enables O(1) or O(log n) lookup times for most route patterns, and it allows middleware to access endpoint metadata (like authorization requirements) before the endpoint executes.

### Can I mix classic and endpoint routing in the same application?

While technically possible, mixing both models is not recommended. The framework maintains the `IRouter` API primarily for backward compatibility with legacy MVC and Web API code. New applications should use endpoint routing exclusively to avoid confusion and potential routing conflicts.

### Where are routes defined in ASP.NET Core?

Routes are defined through `IEndpointRouteBuilder` extension methods in [`EndpointRouteBuilderExtensions.cs`](https://github.com/dotnet/aspnetcore/blob/main/EndpointRouteBuilderExtensions.cs). Common methods include `MapGet`, `MapPost`, `MapControllerRoute`, and `MapRazorPages`. These methods create `Endpoint` objects that get aggregated into the `EndpointDataSource` used by the `Matcher` when `EndpointRoutingMiddleware` processes requests.