Compression is one of the cheapest performance wins on an IIS-hosted site, and it is also one of the most commonly left on the default. Windows Server ships IIS with static and dynamic compression modules that support gzip out of the box, while Brotli only arrives through cross-platform .NET hosting or third-party modules. Choosing between gzip and Brotli, and between static and dynamic compression, changes payload size by 15–25% on typical text assets and CPU load by a similar magnitude in the other direction. This article covers how to enable both, when each makes sense, and how to verify the win.
Static vs Dynamic Compression in IIS
The two modules are not interchangeable and they do not share a cache.
- Static compression: Compresses files on disk once and caches the result under
%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files. Cheap at request time because the work is already done. Ideal for CSS, JS, HTML, and JSON that does not change per request. - Dynamic compression: Compresses each response in memory as it is generated. Hits the CPU on every request but works for anything — including API responses that never exist as a file. More expensive, so keep it scoped to the MIME types that benefit.
The classic mistake is enabling dynamic compression for image/* and video/*. Already-compressed formats get bigger after gzip and you pay CPU for the privilege. Restrict dynamic compression to text and JSON.
Enabling gzip Compression
Install the modules and configure them from an elevated PowerShell session:
Install-WindowsFeature -Name Web-Dyn-Compression, Web-Stat-Compression
Import-Module WebAdministration
# Dynamic: only text-like types
Set-WebConfigurationProperty -PSPath 'IIS:\' `
-Filter "system.webServer/httpCompression" `
-Name "dynamicTypes" -Value @{mimeType='application/json'}
Add-WebConfigurationProperty -PSPath 'IIS:\' `
-Filter "system.webServer/httpCompression/dynamicTypes" `
-Name "." -Value @{mimeType='text/html'}
Also set dynamicCompressionLevel (1–9, default 0 which means no dynamic compression unless a level is set) and the static compression equivalents. Level 4–5 is the usual balance point; above 7 the CPU cost stops paying for the marginal size reduction.
Where Brotli Comes From
IIS itself does not ship a Brotli compression module. You get Brotli in one of three ways:
- .NET hosting with response compression middleware: ASP.NET Core’s
ResponseCompressionmiddleware supports Brotli natively. AddBrotliCompressionProviderand it negotiates Brotli for clients that advertisebr, falling back to gzip. - A reverse proxy: Nginx in front of IIS compresses with Brotli via
ngx_brotli, offloading the work from IIS entirely. - Third-party IIS modules: Community Brotli providers exist but add a maintenance dependency; evaluate before adopting.
// ASP.NET Core Program.cs
builder.Services.AddResponseCompression(o =>
{
o.EnableForHttps = true;
o.Providers.Add<BrotliCompressionProvider>();
o.Providers.Add<GzipCompressionProvider>();
o.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
new[] { "application/json", "image/svg+xml" });
});
Brotli typically beats gzip by 15–20% on HTML and JSON at equivalent CPU. For a text-heavy site that adds up to real bandwidth savings. The configuration choices here sit alongside the broader IIS tuning covered on windows-vps.org if you want to see how compression fits the rest of a hosting stack.
Choosing the Right Setting
A pragmatic policy that covers most sites:
- Static gzip: on for
text/*,application/javascript,application/json,image/svg+xml. - Dynamic gzip: on only for JSON and generated HTML; leave off for images and fonts.
- Brotli: prefer it for dynamic responses when you control the app framework or run a proxy; let gzip remain the fallback.
- Never compress already-compressed binaries — check that
Content-Encodingis not applied to PNG, JPEG, WebP, MP4, or WOFF2.
Verifying the Win and Watching CPU
Do not assume compression is working — check it. From a client, request an asset and inspect the headers:
curl -sI -H "Accept-Encoding: gzip, br" https://example.com/ | findstr /i "content-encoding content-length"
You want to see Content-Encoding: br or gzip and a reduced Content-Length. Then watch the server side: add the % Processor Time and Requests/sec counters in Performance Monitor and compare before and after under load. On a memory-constrained Windows VPS, dynamic compression is a trade of RAM and CPU for bandwidth — if the box is already CPU-bound at peak, enabling it will hurt more than it helps. For most read-heavy sites, static compression alone delivers the bulk of the benefit at almost no runtime cost, and it is the safest place to start before reaching for Brotli.
Compression Safety Nets and Common Pitfalls
A few failure modes catch teams out after they enable compression. Double compression is the first: if a CDN or reverse proxy already compresses a response and IIS compresses it again, the payload grows and clients may reject it. Pick one layer to own the job — usually the edge — and disable compression upstream where it overlaps. The second is stale static caches: when you update a CSS or JS file, IIS may keep serving the old compressed copy from its temporary folder until the source timestamp changes, so bump the file mtime during deploys. The third is TLS interaction — do not enable compression on responses containing secrets, because the old BREACH-style attacks exploit the size difference that compression introduces. Finally, watch the temporary compressed-files folder on a small VPS; it can grow quietly and consume system-drive space, so point it at a data volume or cap its size. Locking down the surrounding IIS surface, including the request-filtering and header settings that travel with these tuning changes, is covered in the server hardening notes on windows-vps.org.



