ASP.NET 9 brings a new way to delivery static files with native compression in different formats. Let’s check out the changes.
Static Files
When working with ASP.NET or Blazor, our static files stays on wwwroot folder, and are served with our application.
Is a common and best practice to compress these files, even minify then to use less network as possible.
However compress and cache files during the development is not always a good idea (specially for caching).
UseStaticFiles
To serve any static files on your ASP.NET application, you just need to add this line of code to your Program.cs.
app.UseStaticFiles();This will automatically search for static files inside your wwwroot folder and that’s it, they’ll be served in your web app.
You can still use the UseStaticFiles if you want to serve local files or do not want to cache/compress then
MapStaticAssets
MapStaticAssets is a newly introduced middleware designed to optimize the delivery of static assets within an application.
It is compatible with all UI frameworks, including Blazor, Razor Pages, and MVC, and often serves as a direct replacement for UseStaticFiles.
app.MapStaticAssets();MapStaticAssets functions by integrating build and publish-time processes to gather information about all the static resources in an application.
This data is then leveraged by the runtime library to efficiently deliver these files to the browser.
MapStaticAssets can substitute UseStaticFiles in most cases, but it is specifically optimized for serving assets that the application recognizes at build and publish time.
If the application needs to serve assets from other locations, such as disk or embedded resources, UseStaticFiles is the preferred choice.
Advantages
MapStaticAssets offers several advantages over UseStaticFiles:
- Build-time compression for all assets in the app: During development, assets are compressed using
gzip, and during publishing, bothgzipandbrotlicompression are applied. This ensures that all assets are minimized in size. - Content-based ETags: The ETags for each resource are generated using a Base64 encoded string of the SHA-256 hash of the content. This guarantees that the browser only re-downloads a file if its content has changed.
The table below illustrates the original and compressed sizes of the CSS and JS files in the default Razor Pages template:
| File | Original | Compressed | % Reduction |
|---|---|---|---|
| bootstrap.min.css | 163 | 17.5 | 89.26% |
| jquery.js | 89.6 | 28 | 68.75% |
| bootstrap.min.js | 78.5 | 20 | 74.52% |
| Total | 331.1 | 65.5 | 80.20% |
The following table shows the original and compressed sizes using the Fluent UI Blazor components library
| File | Original | Compressed | % Reduction |
|---|---|---|---|
| fluent.js | 384 | 73 | 80.99% |
| fluent.css | 94 | 11 | 88.30% |
| Total | 478 | 84 | 82.43% |
For a total of 478 KB uncompressed to 84 KB compressed.
The following table shows the original and compressed sizes using the MudBlazor Blazor components library
| File | Original | Compressed | Reduction |
|---|---|---|---|
| MudBlazor.min.css | 541 | 37.5 | 93.07% |
| MudBlazor.min.js | 47.4 | 9.2 | 80.59% |
| Total | 588.4 | 46.7 | 92.07% |
Optimization occurs automatically when using MapStaticAssets. When a library is added or updated, such as with new JavaScript or CSS, the assets are optimized as part of the build process.
This optimization is particularly advantageous for mobile environments, where bandwidth may be limited or connections may be unreliable.
My tests with .NET 9 Preview 7
I’m running .NET 9 Preview 7 and just created a new Blazor app using the command below.
dotnet new blazor -o BlazorMapStaticSampleThe initial result, in development mode, I could find the following files on wwwroot/bootstrap folder.

Then I ran the build command with -c Release flag to generate the final files for my application.

It compressed other files like app.css but the most impressive ones are from Bootstrap. Good job 🍻
Development VS Production
To deal with these files, the imports on App.razor changed a little bit. Now we have @Assets to import static files.
This will handle compression and any other things for us. In additional we have the <ImportMap /> tag.
<link rel="stylesheet" href="@Assets["bootstrap/bootstrap.min.css"]" />
<link rel="stylesheet" href="@Assets["app.css"]" />
<link rel="stylesheet" href="@Assets["BlazorNewStaticFiles.styles.css"]" />
<ImportMap />Version management by default
By the way, after run my app and check the code source, I could find the following:
<link rel="stylesheet" href="bootstrap/bootstrap.min.bpk8xqwxhs.css" />
<link rel="stylesheet" href="app.da95v2qkru.css" />
<link rel="stylesheet" href="BlazorNewStaticFiles.f5ewiwg5xa.styles.css" />Note that we have some hashs like da95v2qkru on our static files. This is to grant we always have the latest file and can cache it.
If our files changes, this code will change and the browser will have to download it again, updating the cache.
We already had a similar behavior when using append-version tag on Razor, but I like this new way more.
I miss something…
I thin to be perfect there’s just one more little thing to do: Minification
Almost all web applications benefit from minification, and this should be done at build time by default when serving static files.
We could have options like “do not minifiy this file” or “disable minification”, but come on, who want’s to spend more network band?
Conclusion
In conclusion, MapStaticAssets provides a powerful and efficient solution for optimizing the delivery of static assets in ASP.NET applications.
By integrating seamlessly with the build and publish processes, it ensures that assets are compressed, minimized, and served with optimal performance.
Its advanced features, such as content-based ETags and automated optimization, make it particularly well-suited for environments where bandwidth is limited or connections are less reliable.
While it can replace UseStaticFiles in most cases, it also allows for flexibility when serving assets from other sources.
Adopting MapStaticAssets can significantly enhance the performance and user experience of your application.
