Server-side optimization for .NET
ASP.NET Core performance, optimized at the server layer
nginx and Apache shops have had a server-side page optimizer for over a decade. The official
.NET performance advice stops at response compression and a CDN, neither of which transcodes
an image or inlines critical CSS. WeAmp.PageSpeed.AspNetCore is the in-process middleware that closes that gap: one dotnet add package, optimization applied to the responses Kestrel already renders.
Production use requires a commercial license — but the software never locks you out.
The category .NET never had
Response compression shrinks text bytes on the wire. A CDN moves bytes closer to the user. Both are real wins, and both leave the page contents unchanged: the JPEG is still a JPEG, the stylesheet still blocks first paint, the unsized image still shifts the layout. A server-side optimizer works one layer down. It rewrites the response itself — it transcodes the image to a smaller format, extracts the above-the-fold CSS and defers the rest, and adds a content hash so a repeat visit skips the network. That category has existed for nginx and Apache since 2010. On .NET it has been a blind spot.
ModPageSpeed 2.0 went GA on 2026-05-17, and its ASP.NET Core middleware shipped the same day. It runs the same optimization worker the 2.0 nginx module uses, wrapped as an in-process middleware so it lives inside your .NET app instead of in front of it.
Two ways to run it on the Microsoft stack
ASP.NET Core middleware
WeAmp.PageSpeed.AspNetCore
The ModPageSpeed 2.0 in-process middleware. It runs inside your ASP.NET Core app, no
reverse-proxy hop and no separate container. The native worker is bundled per runtime
identifier (linux-x64, linux-arm64, osx-arm64, win-x64), so a single dotnet add package pulls everything — on Linux, Windows, or macOS. Does WebP and AVIF transcoding,
critical CSS, minification, and cache extension.
Native IIS module
mod_pagespeed 1.15
For classic IIS sites, mod_pagespeed 1.15 loads as a native IIS module from a signed MSI. Same filters and configuration as the Apache and nginx modules. WebP image transcoding, critical CSS, and minification, applied in the IIS pipeline. It continues the engine behind IISpeed: that codebase was adopted into the 1.15 IIS port and put through a numbered set of security-hardening fixes before release.
AVIF transcoding and variant-aware caching are ModPageSpeed 2.0 features. The native IIS module on the 1.15 line does WebP, not AVIF. How the C# image pipeline works →
Wiring it into Program.cs
Add the package, then register the middleware early in the pipeline so it wraps the responses your endpoints produce.
dotnet add package WeAmp.PageSpeed.AspNetCore // Program.cs
using WeAmp.PageSpeed.AspNetCore;
var builder = WebApplication.CreateBuilder(args);
// Binds the "PageSpeed" section from IConfiguration (appsettings.json,
// env vars, user secrets).
builder.Services.AddPageSpeed();
var app = builder.Build();
// Optimize responses before they leave Kestrel. Put it early in the
// pipeline, before anything that writes the response body.
app.UsePageSpeed();
app.MapStaticAssets();
app.MapRazorPages();
app.Run(); That is the whole integration for the common case. Optimization runs out of band: a worker process starts automatically alongside your app, reads originals from a shared cache, generates up to 37 variants per image (format, viewport, pixel density, and Save-Data), and writes them back. The middleware serves the matching variant per request. The trade-off is that the first request for a URL returns the original while the worker builds the variants in the background; subsequent requests serve the optimized version from cache. Worker flags and per-transform switches live in the configuration reference.
What server-side optimization fixes — and what it does not
A server-layer optimizer attacks the load-time costs that sit below your application code: byte weight, render-blocking resources, image delivery, and caching. It does not touch your JavaScript runtime behavior. The table maps the common PageSpeed Insights findings to what the middleware actually does, scoped honestly.
| Finding | Coverage | How |
|---|---|---|
| Improve image delivery | Auto-fix | ModPageSpeed transcodes JPEG/PNG/GIF to WebP (and AVIF on 2.0), recompresses with quality-aware encoders, resizes to the rendered display size, and strips EXIF/ICC metadata. Typical result: 40–70% smaller images at visually equivalent quality. |
| Eliminate render-blocking resources | Auto-fix | Render-blocking CSS in the `<head>` is exactly what prioritize_critical_css targets: it extracts the above-the-fold rules, inlines them, and defers the rest. Small JS files inline directly. prioritize_critical_css is marked "test first" — pages with complex CSS-in-JS or aggressive dark-mode swaps can flash unstyled content. Always inline a dark-mode override when using critical CSS. |
| Minify CSS | Auto-fix | ModPageSpeed minifies every CSS file it serves — removing whitespace, comments, and redundant syntax. CoreFilter; enabled by default. |
| Minify JavaScript | Auto-fix | ModPageSpeed minifies every JS file it serves, plus inline `<script>` blocks. CoreFilter; enabled by default. |
| Use efficient cache lifetimes | Auto-fix | ModPageSpeed rewrites static resource URLs to include a content hash and serves them with `Cache-Control: max-age=31536000, immutable`. Repeat visits skip the network entirely. Only applies to assets MPS rewrites (images, CSS, JS that flow through filters). Origin HTML and resources behind `Cache-Control: no-store` are untouched. |
| Image elements have explicit width and height | Auto-fix | `insert_image_dimensions` reads the intrinsic dimensions of each image and adds matching `width`/`height` attributes to the `<img>` tag. |
| Largest Contentful Paint | Assistive | LCP is usually a hero image or above-the-fold text. ModPageSpeed transcodes the LCP image to WebP, resizes it to its rendered size, and removes render-blocking CSS via critical-CSS inlining. If LCP is a video poster, a background-image set by JavaScript, or a font-rendered headline, image filters cannot help directly. |
| Interaction to Next Paint | Client-side | INP measures responsiveness of user interactions after load. It is dominated by event-handler JavaScript and React/Vue re-renders — work ModPageSpeed cannot rewrite without breaking the application. |
| Font display | Client-side | `font-display: swap` is a CSS property that must be declared in the `@font-face` rule by the origin or font provider. ModPageSpeed does not rewrite font-loading semantics. |
| Reduce the impact of third-party code | Client-side | Third-party scripts (analytics, tag managers, ads, chat widgets) are loaded by the origin and run cross-origin. ModPageSpeed does not rewrite or proxy third-party JavaScript. |
INP and most layout shift are your application's job
Interaction to Next Paint is driven by event-handler JavaScript, Blazor interactivity, and hydration — main-thread work the middleware cannot rewrite without changing what your app does. Layout shift from content injected after first paint, or from late-loading web fonts, is application-level too. The middleware can reduce how much script competes for the main thread before the user interacts (minify, defer what is safe to defer), but it will not make a slow click handler fast. If INP is your problem, the fix lives in your C# and JavaScript, not the server layer. Fixing INP on ASP.NET Core →
ASP.NET Core performance: common questions
- How do I improve PageSpeed on ASP.NET Core?
- Optimize the response after Kestrel renders it, the same way nginx and Apache shops have for years. Add the WeAmp.PageSpeed.AspNetCore middleware with one
dotnet add package; it transcodes images to WebP and AVIF, resizes them to their rendered size, inlines critical CSS, minifies CSS and JavaScript, and cache-extends static assets. Response compression and a CDN move bytes faster but do not change what those bytes are; this middleware changes the bytes. - Is there an ASP.NET Core image optimization middleware?
- Yes. WeAmp.PageSpeed.AspNetCore is an in-process ASP.NET Core middleware for ModPageSpeed 2.0, published and indexed on nuget.org. It transcodes JPEG, PNG, and GIF to WebP and AVIF, resizes images to their rendered display size, and serves the right variant per request from a shared cache. The native worker is bundled per runtime identifier (linux-x64, linux-arm64, osx-arm64, win-x64), so a single
dotnet add packageinstalls everything — no separate native module to compile or register. - What is the IIS PageSpeed module?
- mod_pagespeed 1.15 ships as a native IIS module on Windows, installed from a signed MSI. It loads into the IIS pipeline in-process and applies the classic filter set — WebP image transcoding, critical-CSS inlining, CSS and JavaScript minification, and content-hashed cache extension — using the same configuration the Apache and nginx modules use. It continues the engine that powered IISpeed: the IISpeed codebase was adopted into the 1.15 IIS port and put through a numbered set of security-hardening fixes as a merge gate before release.
- I have an IISpeed license. What do I move to?
- IISpeed is deprecated, and its license transfers free to mod_pagespeed 1.15 or ModPageSpeed 2.0. If you want to stay on classic IIS, install the signed IIS MSI for 1.15. If you are on ASP.NET Core, the WeAmp.PageSpeed.AspNetCore NuGet middleware is the documented path. The 1.15 IIS port adopted the IISpeed codebase wholesale, so the optimization behavior is the one you already ran.
- Will a server-side optimizer fix my INP or layout shift?
- Not directly. INP is dominated by your own JavaScript main-thread work — event handlers, Blazor interactivity, hydration — which a server-layer optimizer does not rewrite. Layout shift (CLS) from injected content or late-loading fonts is also application-level. What the middleware fixes reliably is byte weight, render-blocking CSS, image delivery, and caching: the load-time costs that sit below your application code. It will not make a slow click handler fast.
- Does it work outside IIS, on Linux or in containers?
- Yes. WeAmp.PageSpeed.AspNetCore runs wherever ASP.NET Core runs: the native worker is bundled for linux-x64, linux-arm64, osx-arm64, win-x64, so the same middleware works on Linux containers, Windows, and macOS development machines. It does not require IIS. The signed IIS MSI is a separate option for teams running classic IIS who want a native module rather than middleware.
Add it to your .NET app
One dotnet add package WeAmp.PageSpeed.AspNetCore, one app.UsePageSpeed(), and the responses Kestrel renders get optimized before they leave the process. It
optimizes immediately, licensed or not.
Production use requires a commercial license — but the software never locks you out.
See also:
- ASP.NET Core configuration — middleware options, worker flags, and per-transform switches
- ASP.NET Core image optimization in C# — how the WebP and AVIF pipeline works from .NET
- The ASP.NET Core middleware — where it sits in the request pipeline
- IISpeed alternative — the free license-transfer path for IISpeed customers
- Core Web Vitals — which metrics the server layer moves, and which it does not
- WeAmp.PageSpeed.Sidecar on NuGet — the out-of-process 1.15 sidecar (bundles nginx 1.30.2) for teams that want the 1.15 engine behind a .NET reverse proxy
ASP.NET Core, IIS, and Windows are trademarks of Microsoft Corporation; other product names are trademarks of their respective owners. We-Amp B.V. is not affiliated with or endorsed by Microsoft. We-Amp helped maintain mod_pagespeed and prepared its last couple of releases across the Google and Apache incubator eras.