Updated October 2026: the original post covered BuildBundlerMinifier for ASP.NET Core 2.0. That package still works in many projects but hasn't had a release in years, so this update adds a tested WebOptimizer setup for .NET 8 and .NET 10 and explains what .NET 9's MapStaticAssets does (and doesn't) replace.
What Is Bundling and Minification?
Bundling combines several CSS or JavaScript files into one file, so the browser makes fewer requests. Minification removes whitespace, comments and long variable names, so each file is smaller. Together they make pages load faster, which is better for your users and for search rankings. Tools like PageSpeed Insights flag unminified and render-blocking files.
Your Options in ASP.NET Core Today
| Option | When it runs | Good for |
|---|---|---|
BuildBundlerMinifier + bundleconfig.json | At build time | Existing projects already using it |
| LigerShark.WebOptimizer.Core | At runtime (cached) | New projects that want bundling with no Node.js |
| MapStaticAssets (.NET 9+) | At build/publish time | Compression, fingerprinting and caching of static files (not bundling) |
| Node tools (esbuild, Vite) | At build time | Apps that already have a front-end build |
Option 1: BuildBundlerMinifier and bundleconfig.json
Add the BuildBundlerMinifier NuGet package to your project, then list your files, in the order they must load, in a bundleconfig.json file in the project root:
[
{
"outputFileName": "wwwroot/css/site.min.css",
"inputFiles": [
"wwwroot/css/site.css",
"wwwroot/css/custom.css"
]
},
{
"outputFileName": "wwwroot/js/site.min.js",
"inputFiles": [
"wwwroot/js/site.js"
],
"minify": {
"enabled": true,
"renameLocals": true
},
"sourceMap": false
}
]
Each outputFileName is created when the project builds, from its inputFiles. Build in Visual Studio or run dotnet build, and reference the .min files in your layout.
About the dotnet bundle command: it came from the separate BundlerMinifier.Core CLI tool, installed with the old DotNetCliToolReference mechanism that current .NET SDKs no longer support. With BuildBundlerMinifier you don't need it; bundling runs as part of dotnet build.
Option 2: WebOptimizer (Recommended for New Projects)
WebOptimizer bundles and minifies in memory when a bundle is first requested, then caches it, so there are no generated files to commit or forget. Install LigerShark.WebOptimizer.Core and configure the bundles in Program.cs:
// dotnet add package LigerShark.WebOptimizer.Core
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddWebOptimizer(pipeline =>
{
// Bundles are built and minified in memory at runtime, then cached.
pipeline.AddCssBundle("/css/bundle.css", "css/site.css", "css/custom.css");
pipeline.AddJavaScriptBundle("/js/bundle.js", "js/site.js");
});
var app = builder.Build();
app.UseWebOptimizer(); // must come before UseStaticFiles
app.UseStaticFiles();
app.MapGet("/", () => Results.Content(
"""<link rel="stylesheet" href="/css/bundle.css"><script src="/js/bundle.js"></script>""",
"text/html"));
app.Run();
Tested on .NET 10: with a two-file CSS bundle and a JavaScript file, /css/bundle.css returned body{color:#f00}.x{margin:0} and /js/bundle.js returned the minified script with local variables renamed.
In Razor views, use the individual files in development (easier debugging) and the bundle elsewhere. WebOptimizer's tag helpers add a cache-busting version hash to bundle URLs automatically:
@* _Layout.cshtml: register the tag helpers once in _ViewImports.cshtml: @addTagHelper *, WebOptimizer.Core *@
<environment include="Development">
<link rel="stylesheet" href="~/css/site.css" />
<link rel="stylesheet" href="~/css/custom.css" />
</environment>
<environment exclude="Development">
<link rel="stylesheet" href="~/css/bundle.css" />
</environment>
<script src="~/js/bundle.js"></script>
Option 3: MapStaticAssets in .NET 9 and Later
.NET 9 introduced app.MapStaticAssets() as the replacement for UseStaticFiles() in new templates. At build and publish time it gzip- and Brotli-compresses your static files, fingerprints them for long-lived caching, and serves the right version with ETags. It doesn't combine files, so pair it with one of the bundling options above if you have many CSS or JS files. With HTTP/2 and HTTP/3, a handful of separate, compressed and cached files is often fine.
Updating Files and Browser Caching
If you overwrite a bundle with the same file name, browsers may keep using the cached old version. Add asp-append-version="true" to <link> and <script> tags for files served from wwwroot; ASP.NET Core appends a hash of the file contents, so the URL changes whenever the file does. WebOptimizer and MapStaticAssets handle this for you.
Frequently Asked Questions
Is BuildBundlerMinifier still supported?
It still works in many projects, but it hasn't had a new release in years. For new projects, use WebOptimizer or a Node-based build tool.
What is bundleconfig.json?
The configuration file used by BuildBundlerMinifier (and the older Visual Studio Bundler & Minifier extension). Each entry lists input files and the output file to create.
Does ASP.NET Core have built-in bundling?
No. ASP.NET Core never shipped the System.Web.Optimization bundling from ASP.NET MVC 5. Use a library such as WebOptimizer or a front-end build tool; .NET 9+ adds built-in compression and fingerprinting with MapStaticAssets.

