# How to Configure File Upload Size Limits in ASP.NET Core Minimal APIs

> Learn to configure file upload size limits in ASP.NET Core minimal APIs. Control Kestrel and form limits, and apply per-endpoint overrides with request size attributes for secure and efficient file handling.

- Repository: [.NET Platform/skills](https://github.com/dotnet/skills)
- Tags: how-to-guide
- Published: 2026-07-11

---

**Configure both Kestrel's `MaxRequestBodySize` (default 30 MiB) and `FormOptions.MultipartBodyLengthLimit` (default 128 MiB) to handle file uploads in ASP.NET Core minimal APIs, and use `[RequestSizeLimit]` or `[DisableRequestSizeLimit]` attributes for per-endpoint overrides.**

ASP.NET Core minimal APIs automatically bind `IFormFile` and `IFormFileCollection` parameters from `multipart/form-data` requests starting in .NET 8. To prevent "Request body too large" exceptions, you must configure size limits at two independent layers of the request pipeline, as documented in the `dotnet/skills` repository's minimal-api-file-upload skill.

## Understanding the Two-Layer Limit Architecture

File uploads in minimal APIs are constrained by two separate subsystems that operate at different stages of request processing:

- **Kestrel request body limit**: Controls the maximum raw HTTP payload the server accepts (default 30 MiB)
- **FormOptions multipart limit**: Governs the parsed multipart body size during model binding (default 128 MiB)

If you increase only one limit, the other will reject large uploads. According to the skill documentation in [`plugins/dotnet-aspnetcore/skills/minimal-api-file-upload/SKILL.md`](https://github.com/dotnet/skills/blob/main/plugins/dotnet-aspnetcore/skills/minimal-api-file-upload/SKILL.md), both must be configured explicitly for production scenarios.

## Configuring Global Upload Limits

Set application-wide limits using the `WebApplicationBuilder` in [`Program.cs`](https://github.com/dotnet/skills/blob/main/Program.cs).

### Kestrel Request Body Size

Configure the `MaxRequestBodySize` property via `ConfigureKestrel`:

```csharp
var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(options =>
{
    // Set global limit to 10 MiB
    options.Limits.MaxRequestBodySize = 10 * 1024 * 1024;
});

```

### Multipart Form Data Limits

Configure the `FormOptions` via the dependency injection container:

```csharp
builder.Services.Configure<FormOptions>(options =>
{
    // Multipart body size limit (default is 128 MiB)
    options.MultipartBodyLengthLimit = 10 * 1024 * 1024;
    
    // Optional: limit individual form fields
    options.ValueLengthLimit = 1 * 1024 * 1024;
    
    // Optional: limit multipart headers per section
    options.MultipartHeadersLengthLimit = 16 * 1024;
});

```

## Per-Endpoint Size Limit Overrides

For endpoints that handle larger files or require streaming, apply attributes directly to the route handler.

### Increasing Limits for Specific Endpoints

Use `[RequestSizeLimit]` to raise the allowance for a single route:

```csharp
app.MapPost("/upload-large",
    [RequestSizeLimit(200_000_000)] // 200 MiB
    (IFormFile file) => 
    {
        return Results.Ok(new { file.FileName, file.Length });
    });

```

### Removing Limits for Streaming Uploads

Use `[DisableRequestSizeLimit]` when processing files with `MultipartReader` to avoid buffering:

```csharp
app.MapPost("/upload-stream",
    [DisableRequestSizeLimit]
    async (HttpContext ctx) =>
{
    var mediaType = MediaTypeHeaderValue.Parse(ctx.Request.ContentType);
    var boundary = HeaderUtilities.RemoveQuotes(mediaType.Boundary).Value;
    var reader = new MultipartReader(boundary, ctx.Request.Body);
    
    while (await reader.ReadNextSectionAsync() is { } section)
    {
        // Stream directly to storage without buffering
    }
    
    return Results.Ok();
});

```

## Handling Anti-Forgery Validation

By default, .NET 8 minimal API templates enable `UseAntiforgery()`, which automatically validates anti-forgery tokens on all form-bound endpoints. For API-only uploads using JWT authentication or other stateless mechanisms, disable this validation:

```csharp
app.MapPost("/api/upload", (IFormFile file) => 
{
    return Results.Ok(file.FileName);
})
.DisableAntiforgery();

```

Only disable anti-forgery for stateless API endpoints. Keep it enabled for cookie-based authentication scenarios.

## Complete Implementation Example

The following [`Program.cs`](https://github.com/dotnet/skills/blob/main/Program.cs) demonstrates global limits, per-endpoint overrides, and security configuration:

```csharp
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Net.Http.Headers;

var builder = WebApplication.CreateBuilder(args);

// 1. Configure Kestrel global limit (30 MiB default)
builder.WebHost.ConfigureKestrel(options =>
{
    options.Limits.MaxRequestBodySize = 10 * 1024 * 1024;
});

// 2. Configure FormOptions global limit (128 MiB default)
builder.Services.Configure<FormOptions>(options =>
{
    options.MultipartBodyLengthLimit = 10 * 1024 * 1024;
    options.ValueLengthLimit = 1 * 1024 * 1024;
    options.MultipartHeadersLengthLimit = 16 * 1024;
});

var app = builder.Build();

// 3. Standard upload with global limits
app.MapPost("/upload", (IFormFile file) =>
{
    // Validate content type and file signature here
    return Results.Ok(new { file.FileName, file.Length });
});

// 4. Large file upload with per-endpoint limit
app.MapPost("/upload-large",
    [RequestSizeLimit(200_000_000)]
    (IFormFile file) => Results.Ok(new { file.FileName, file.Length })
);

// 5. Streaming upload without size limits
app.MapPost("/upload-stream",
    [DisableRequestSizeLimit]
    async (HttpContext ctx) =>
{
    if (!MediaTypeHeaderValue.TryParse(ctx.Request.ContentType, out var mediaType))
        return Results.BadRequest("Invalid Content-Type");
    
    var boundary = HeaderUtilities.RemoveQuotes(mediaType.Boundary).Value;
    if (string.IsNullOrWhiteSpace(boundary))
        return Results.BadRequest("Missing boundary");
    
    var reader = new MultipartReader(boundary, ctx.Request.Body);
    while (await reader.ReadNextSectionAsync() is { } section)
    {
        // Process stream without buffering to memory
    }
    
    return Results.Ok();
});

// 6. API endpoint without anti-forgery (for JWT scenarios)
app.MapPost("/api/upload", (IFormFile file) => Results.Ok(file.FileName))
   .DisableAntiforgery();

app.Run();

```

## Summary

- **Configure both layers**: Set `MaxRequestBodySize` in Kestrel and `MultipartBodyLengthLimit` in `FormOptions` to avoid rejection at either the server or form-parsing layer.
- **Use attributes for exceptions**: Apply `[RequestSizeLimit]` or `[DisableRequestSizeLimit]` to individual endpoints that exceed global limits or require streaming.
- **Manage anti-forgery**: Call `.DisableAntiforgery()` only on stateless API endpoints, not on cookie-authenticated routes.
- **Validate content**: Always verify MIME types and file signatures server-side, regardless of size limits.

## Frequently Asked Questions

### Why do I still get "Request body too large" errors after configuring limits?

This occurs when you only configure one of the two required limit layers. **Kestrel's `MaxRequestBodySize`** (default 30 MiB) controls the raw HTTP payload, while **ASP.NET Core's `FormOptions.MultipartBodyLengthLimit`** (default 128 MiB) controls the parsed multipart body. You must configure both via `builder.WebHost.ConfigureKestrel()` and `builder.Services.Configure<FormOptions>()` respectively, as shown in the [`plugins/dotnet-aspnetcore/skills/minimal-api-file-upload/SKILL.md`](https://github.com/dotnet/skills/blob/main/plugins/dotnet-aspnetcore/skills/minimal-api-file-upload/SKILL.md) documentation.

### How do I completely disable file upload size limits for a specific endpoint?

Apply the `[DisableRequestSizeLimit]` attribute to the route handler. This removes both the Kestrel request body limit and the FormOptions multipart limit for that endpoint, enabling scenarios like `MultipartReader` streaming where you process the upload in chunks without buffering the entire file to memory or disk.

### Do file upload endpoints require anti-forgery token validation?

Yes, by default. .NET 8 minimal API templates enable `UseAntiforgery()` automatically, which validates anti-forgery tokens on all form-bound endpoints including those accepting `IFormFile`. For stateless API clients using JWT Bearer authentication, chain `.DisableAntiforgery()` on the endpoint route. Never disable antiforgery on endpoints that accept cookie-based authentication.

### What's the difference between RequestSizeLimit and DisableRequestSizeLimit?

**`[RequestSizeLimit(bytes)]`** sets a specific byte limit for the endpoint, overriding the global configuration with a higher or lower value. **`[DisableRequestSizeLimit]`** removes size constraints entirely, allowing uploads of any size. Use `RequestSizeLimit` when you know the maximum expected file size; use `DisableRequestSizeLimit` only when implementing custom streaming logic with `MultipartReader` that handles backpressure and storage limits manually.