> For the complete documentation index, see [llms.txt](https://docs.umbraco.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.umbraco.com/ai-in-umbraco/17.latest/extending/middleware/middleware-ordering.md).

# Middleware Ordering

Middleware execution order is controlled through the collection builder. The order determines which middleware runs first and how they wrap each other.

## Understanding Order

Middleware is applied in registration order, creating nested wrappers. Each middleware's `Apply` method is called on the current client, so the first registered middleware wraps the underlying client, and the last registered middleware wraps everything else:

```
Registration order: A, B, C

Result: C wraps (B wraps (A wraps Client))

Execution flow:
  Request  → C → B → A → Client → Response
  Response ← C ← B ← A ← Client ←
```

The **last** registered middleware is the **outermost** wrapper and sees requests first.

## Builder Methods

The collection builder provides methods to control ordering:

| Method                       | Description                         |
| ---------------------------- | ----------------------------------- |
| `Append<T>()`                | Add middleware at the end           |
| `InsertBefore<TBefore, T>()` | Insert before a specific middleware |
| `InsertAfter<TAfter, T>()`   | Insert after a specific middleware  |
| `Remove<T>()`                | Remove a middleware                 |

## Basic Ordering

{% code title="MyComposer.cs" %}

```csharp
using Umbraco.AI.Extensions;
using Umbraco.Cms.Core.Composing;

public class MyComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        builder.AIChatMiddleware()
            .Append<LoggingMiddleware>()      // Innermost (wraps client first)
            .Append<CachingMiddleware>()      // Wraps Logging
            .Append<TracingMiddleware>();     // Outermost (sees requests first)
    }
}
```

{% endcode %}

## Inserting Relative to Others

When extending existing middleware pipelines:

{% code title="Inserting Middleware" %}

```csharp
public class ExtendingComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        // Insert metrics just inside logging (so metrics see the call after logging)
        builder.AIChatMiddleware()
            .InsertBefore<LoggingMiddleware, MetricsMiddleware>();

        // Insert rate limiting just outside authentication
        builder.AIChatMiddleware()
            .InsertAfter<AuthMiddleware, RateLimitMiddleware>();
    }
}
```

{% endcode %}

## Removing Middleware

Remove middleware added by other composers:

{% code title="Removing Middleware" %}

```csharp
public class CustomComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        builder.AIChatMiddleware()
            .Remove<DefaultLoggingMiddleware>()
            .Append<MyCustomLoggingMiddleware>();
    }
}
```

{% endcode %}

## Embedding Middleware Ordering

The same methods work for embedding middleware:

{% code title="Embedding Ordering" %}

```csharp
public class MyComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        builder.AIEmbeddingMiddleware()
            .Append<MetricsEmbeddingMiddleware>()
            .Append<CachingEmbeddingMiddleware>()
            .Append<NormalizationEmbeddingMiddleware>();
    }
}
```

{% endcode %}

## Common Patterns

As a rule of thumb, place logging and error handling middleware last (outermost) so they capture the full request lifecycle, and place caching middleware first (innermost) so cached responses skip other middleware.

## Multiple Composers

When multiple composers add middleware, they combine in composer execution order:

{% code title="ComposerA.cs" %}

```csharp
[ComposeAfter(typeof(UmbracoAIComposer))]
public class ComposerA : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        builder.AIChatMiddleware()
            .Append<MiddlewareA>();
    }
}
```

{% endcode %}

{% code title="ComposerB.cs" %}

```csharp
[ComposeAfter(typeof(ComposerA))]
public class ComposerB : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        builder.AIChatMiddleware()
            .Append<MiddlewareB>()
            .InsertBefore<MiddlewareA, MiddlewareC>(); // Insert before A
    }
}
```

{% endcode %}

Use `[ComposeBefore]` and `[ComposeAfter]` attributes to control composer order.

{% hint style="info" %}
Middleware order is set at application startup and cannot change at runtime.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.umbraco.com/ai-in-umbraco/17.latest/extending/middleware/middleware-ordering.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
