# How to Serve Files with ASP.NET Core FileProviders: A Complete Guide

> Learn to serve files with ASP.NET Core FileProviders. Access content from disks, embedded resources, or custom sources easily and efficiently. Get the complete guide.

- Repository: [.NET Platform/aspnetcore](https://github.com/dotnet/aspnetcore)
- Tags: how-to-guide
- Published: 2026-06-20

---

**ASP.NET Core abstracts file access through the `IFileProvider` interface, enabling you to serve content from physical disks, embedded resources, or custom sources without changing middleware logic.**

The `dotnet/aspnetcore` repository implements a flexible file serving pipeline built on the `IFileProvider` abstraction. This design allows the framework to serve static files, compile Razor views, and resolve Tag Helper glob patterns using a unified interface. Whether you are exposing files from the local filesystem, embedded assembly resources, or a custom cloud storage backend, understanding these providers is essential for building maintainable ASP.NET Core applications.

## Understanding the IFileProvider Interface

The **IFileProvider** interface defines the contract for all file access in ASP.NET Core. It exposes methods to retrieve `IFileInfo` and `IDirectoryContents` for a given virtual path, isolating your application from specific storage implementations.

According to the source code in [`src/Middleware/StaticFiles/src/StaticFileMiddleware.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/StaticFiles/src/StaticFileMiddleware.cs), the middleware delegates all file resolution to an `IFileProvider` instance configured through `StaticFileOptions`. This means the middleware itself contains no filesystem-specific logic—it simply asks the provider for a file and streams the result if found.

## Built-in FileProvider Implementations

ASP.NET Core ships with three primary implementations that cover most scenarios. Each provider implements `IFileInfo` to expose file metadata and stream access.

### PhysicalFileProvider

The **PhysicalFileProvider** maps virtual paths to a directory on disk. By default, when you call `app.UseStaticFiles()` without arguments, the framework creates a `PhysicalFileProvider` pointing to the web root (`wwwroot`) folder.

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

app.UseStaticFiles(); // Uses PhysicalFileProvider for wwwroot
app.Run();

```

### EmbeddedFileProvider

The **EmbeddedFileProvider** serves files compiled into an assembly as embedded resources. This is ideal for serving static assets from class libraries or plugins where you cannot rely on external files.

```csharp
var embeddedProvider = new EmbeddedFileProvider(
    typeof(Program).Assembly, "MyApp.Embedded");

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = embeddedProvider,
    RequestPath = "/embedded"
});

```

### CompositeFileProvider

The **CompositeFileProvider** merges multiple providers into a single logical view. When resolving a path, it queries providers in the order specified and returns the first match found.

```csharp
var composite = new CompositeFileProvider(
    new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "wwwroot")),
    new EmbeddedFileProvider(typeof(Program).Assembly, "MyApp.Embedded"));

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = composite
});

```

## Configuring Static File Middleware

The **StaticFileMiddleware** (defined in [`src/Middleware/StaticFiles/src/StaticFileMiddleware.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/StaticFiles/src/StaticFileMiddleware.cs)) handles HTTP requests for static content. It uses `StaticFileOptions` (located in [`src/Middleware/StaticFiles/src/StaticFileOptions.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/StaticFiles/src/StaticFileOptions.cs)) to determine which `IFileProvider` to query and how to map request paths to virtual paths.

When a request arrives, the middleware calls `FileProvider.GetFileInfo(requestPath)`. If the returned `IFileInfo` has `Exists == true` and `IsDirectory == false`, the middleware streams the file to the response with appropriate content-type headers, caching directives, and range request support.

To serve files from a custom directory outside of `wwwroot`, configure the options explicitly:

```csharp
var env = app.Environment;
var customProvider = new PhysicalFileProvider(
    Path.Combine(env.ContentRootPath, "SharedFiles"));

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = customProvider,
    RequestPath = "/shared"
});

```

## FileProviders in Razor and Tag Helpers

Beyond static file serving, the `IFileProvider` abstraction powers other subsystems in the `dotnet/aspnetcore` framework.

### Razor Runtime Compilation

In [`src/Mvc/Mvc.Razor.RuntimeCompilation/src/FileProviderRazorProjectFileSystem.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Razor.RuntimeCompilation/src/FileProviderRazorProjectFileSystem.cs), the **FileProviderRazorProjectFileSystem** bridges Razor's project system to an `IFileProvider`. This allows the runtime compiler to locate and watch `.cshtml` files for changes, even when those files reside in non-standard locations.

```csharp
builder.Services.AddRazorPages()
    .AddRazorRuntimeCompilation(options =>
    {
        options.FileProviders.Add(
            new PhysicalFileProvider(
                Path.Combine(env.ContentRootPath, "RazorPages")));
    });

```

### Tag Helper Globbing

The globbing infrastructure for Tag Helpers (such as `<script src="~/js/**/*.js">`) relies on [`FileProviderGlobbingFile.cs`](https://github.com/dotnet/aspnetcore/blob/main/FileProviderGlobbingFile.cs) and [`FileProviderGlobbingDirectory.cs`](https://github.com/dotnet/aspnetcore/blob/main/FileProviderGlobbingDirectory.cs) in `src/Mvc/Mvc.TagHelpers/src/`. These classes adapt the `IFileProvider` interface to the globbing pattern matcher, enabling wildcard expansion over any file provider implementation.

## Summary

- **IFileProvider** is the core abstraction that decouples ASP.NET Core from specific storage implementations.
- Use **PhysicalFileProvider** for disk-based files, **EmbeddedFileProvider** for assembly resources, and **CompositeFileProvider** to combine multiple sources.
- Configure **StaticFileOptions** to customize the `FileProvider` used by `StaticFileMiddleware` for serving static content.
- The same abstraction supports **Razor runtime compilation** and **Tag Helper globbing** through adapter classes like `FileProviderRazorProjectFileSystem`.

## Frequently Asked Questions

### What is the default FileProvider when calling UseStaticFiles()?

When you invoke `app.UseStaticFiles()` without arguments, ASP.NET Core automatically creates a **PhysicalFileProvider** that points to the application's web root directory (typically `wwwroot`). This provider handles all requests to static files unless you explicitly override it in `StaticFileOptions`.

### Can I serve files from outside the web root folder?

Yes. Create a new **PhysicalFileProvider** instance pointing to your desired directory and pass it to `StaticFileOptions.FileProvider`. Set the `RequestPath` property to specify the URL prefix that maps to this location, allowing you to serve files from any accessible path on the filesystem.

### How do I serve files embedded in a Razor Class Library?

Use the **EmbeddedFileProvider** from the `Microsoft.Extensions.FileProviders.Embedded` namespace. Pass the assembly containing your resources and the optional namespace prefix to the constructor, then register it in `StaticFileOptions` or as part of a `CompositeFileProvider` if you need to merge it with physical files.

### Why would I need a custom IFileProvider implementation?

Custom implementations allow you to serve files from sources not supported by the built-in providers, such as cloud storage services (Azure Blob Storage, AWS S3), databases, or network shares. Because `StaticFileMiddleware` and Razor compilation only depend on the `IFileProvider` interface, swapping the implementation requires no changes to the consuming code.