Skip to main content
SEMastery
ASP.NETbeginner

Response Compression in ASP.NET Core: A Beginner's Guide

Learn how response compression works in ASP.NET Core. Shrink Gzip and Brotli responses, speed up your API, and avoid common pitfalls.

11 min readUpdated March 20, 2026

Imagine you are packing clothes for a long train journey across India. If you just throw everything loose into your bag, it fills up fast and barely closes. But if you roll each shirt tightly and use a vacuum bag to squeeze the air out, the same clothes take half the space. The clothes are the same when you unpack them. You just sent them in a smaller, tighter bundle.

Response compression in ASP.NET Core does exactly this for your web pages and API data. The server squeezes the response into a smaller bundle before sending it over the internet. The browser unpacks it on the other side. The user sees the same page, but it arrives faster and uses less data. On a slow mobile connection, this can feel like magic.

In this guide we will learn what compression is, how ASP.NET Core does it, how to switch it on, and the mistakes to avoid. We will keep it simple and friendly. By the end you will be able to add compression to your own app with confidence.

Why compression matters

Every time someone opens your website, the server sends data over the network. Text data like HTML, CSS, JavaScript and JSON is very "repetitive". The same words and patterns appear again and again. Compression spots these repeats and writes them in a shorter way.

Smaller responses mean three good things:

  • Pages load faster, especially on slow networks.
  • Users spend less mobile data, which they care about a lot.
  • Your server and bandwidth bills can go down.

Text files often shrink by 70 to 90 percent. That is a huge win for almost no effort.

Without compression the full-size response travels the network. With compression a small bundle travels instead.

How the browser and server agree

Compression is a polite conversation. The browser does not force the server. They agree on a format first. This handshake uses HTTP headers.

When a browser asks for a page, it sends a header that lists the formats it understands:

Accept-Encoding: gzip, br

Here gzip means Gzip and br means Brotli. These are two popular squeezing methods. The server reads this list, picks one it also supports, compresses the response, and adds a header to say what it used:

Content-Encoding: br

Now the browser knows it received a Brotli bundle and unpacks it automatically. The user never sees any of this. It just works.

The Accept-Encoding and Content-Encoding headers let both sides agree on a format.

Gzip vs Brotli

ASP.NET Core ships with two built-in compression providers: Gzip and Brotli. Both come ready to use. You do not install anything extra for them.

Brotli is newer and usually squeezes text smaller than Gzip. Almost every modern browser supports it. Gzip is older but supported everywhere, including old clients. ASP.NET Core is smart here. If the browser supports Brotli, it uses Brotli. If not, it falls back to Gzip. You get the best of both without extra work.

ProviderStrengthBrowser supportDefault choice
Brotli (br)Smaller output for textAll modern browsersUsed first when supported
Gzip (gzip)Reliable and universalEvery browser, even old onesUsed as a fallback

Think of Brotli as the vacuum bag and Gzip as a sturdy rolled bundle. The vacuum bag is tighter, but the rolled bundle always works.

Turning compression on

Let us add compression to a real app. There are two simple steps. First you register the service. Then you tell the middleware pipeline to use it. Here is a minimal Program.cs for .NET 10.

var builder = WebApplication.CreateBuilder(args);
 
// Step 1: register response compression
builder.Services.AddResponseCompression(options =>
{
    // also compress over HTTPS (read the security note below first)
    options.EnableForHttps = true;
});
 
var app = builder.Build();
 
// Step 2: use it early in the pipeline
app.UseResponseCompression();
 
app.MapGet("/", () => "Hello from a compressed response!");
 
app.Run();

That is the whole thing. By default this gives you both Brotli and Gzip. The order matters a lot, which we will cover next.

Middleware order is important

ASP.NET Core handles a request by passing it through a line of middleware, one after another. The order is like an assembly line in a factory. Each station does its job and passes the work along.

Compression must run before anything that writes the response body. If you put it too late, the data is already sent and there is nothing left to squeeze. A good rule: call app.UseResponseCompression() near the top, before static files and before your endpoints.

Where compression sits in the pipeline

Request
Compression
Routing
Endpoint
Response

Steps

1

Request

Browser asks for data

2

Compression

Wraps the output stream

3

Routing

Finds the handler

4

Endpoint

Builds the body

5

Response

Squeezed bundle leaves

Compression must come before the response body is written.

If you get the order wrong, you will simply see no compression. There is no crash and no error message. That makes this a sneaky bug. So always double-check the order if compression is not working.

Choosing a compression level

Squeezing harder makes the bundle smaller but uses more CPU time. ASP.NET Core lets you pick how hard to squeeze. There are three levels.

LevelWhat it doesWhen to use
FastestLight squeeze, low CPUServer CPU is busy
OptimalBalanced squeezeGood default for most apps
SmallestSizeHardest squeeze, more CPUBandwidth matters most

By default the providers use Fastest. For most websites Optimal is a nice middle ground. Here is how you set the level for both providers.

using System.IO.Compression;
using Microsoft.AspNetCore.ResponseCompression;
 
builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
    options.Providers.Add<BrotliCompressionProvider>();
    options.Providers.Add<GzipCompressionProvider>();
});
 
// tune each provider's effort
builder.Services.Configure<BrotliCompressionProviderOptions>(o =>
{
    o.Level = CompressionLevel.Optimal;
});
 
builder.Services.Configure<GzipCompressionProviderOptions>(o =>
{
    o.Level = CompressionLevel.Optimal;
});

Test your own app before deciding. Measure the response size and the CPU use. The right level depends on your traffic and your server.

Which content types get compressed

ASP.NET Core does not compress everything. It only squeezes a set of "safe" content types like HTML, CSS, JavaScript, JSON and XML. This is on purpose. Some files should never be compressed.

Images such as JPEG and PNG, video files such as MP4, and archives such as ZIP are already compressed. Squeezing them again wastes CPU and can make them slightly bigger. So the middleware leaves them alone.

If your API sends a custom content type, you can add it to the list. For example, to compress SVG images, which are really text:

builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
    options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
        new[] { "image/svg+xml" });
});

Be careful here. Only add text-like types. Adding image/png would just waste effort.

A simple decision the middleware makes for each response.

The security note: CRIME and BREACH

You may have noticed EnableForHttps is turned off by default. There is a real reason. Two attacks called CRIME and BREACH can sometimes guess secret data by watching how the compressed size changes. This works best on HTTPS pages that mix secret tokens with attacker-controlled input.

ASP.NET Core plays safe. It keeps compression off for HTTPS until you turn it on yourself. For most apps that serve public content, turning it on is fine. If your responses contain secrets like anti-forgery tokens next to user input, be more careful. Anti-forgery tokens and not reflecting user input into compressed secret responses help reduce the risk.

The short, beginner-friendly advice: turn on EnableForHttps for normal public pages and static assets, and think twice before compressing pages that mix secrets with user input.

Deciding on HTTPS compression

Public content?
Secrets mixed in?
Enable
Be cautious

Steps

1

Public content?

Marketing, blog, static files

2

Secrets mixed in?

Tokens plus user input

3

Enable

Safe to compress

4

Be cautious

Review before enabling

A quick mental checklist before enabling EnableForHttps.

Should the server or a proxy do it?

There is one more thing to know. Compression does not have to happen inside your ASP.NET Core app. A web server or reverse proxy in front of your app, such as Nginx, IIS or Apache, can do it instead. These servers are often faster at it and free up your app's CPU.

So when should you use the built-in middleware? Use it when no proxy is doing the job, or when you are hosting somewhere simple like a single container. If you already run Nginx or IIS in front and it compresses responses, you usually do not need the middleware too. Pick one place to compress, not both. Compressing twice is wasted work.

A good plan for many teams: let the reverse proxy handle compression in production, and use the middleware during local development or for simple hosting setups.

A quick test to prove it works

After you wire everything up, you want to confirm it actually compresses. The easiest way is your browser's developer tools. Open the Network tab, reload the page, click a request, and look at the response headers. You should see Content-Encoding: br or Content-Encoding: gzip. You should also see the transferred size is smaller than the actual size.

You can also test from the command line. Sending an Accept-Encoding header tells the server you accept compression, and the response headers will show what it used.

// A tiny endpoint that returns a big repetitive string,
// perfect for seeing compression shrink it a lot.
app.MapGet("/big", () =>
{
    var text = string.Concat(Enumerable.Repeat("hello world ", 5000));
    return Results.Text(text);
});

Hit this endpoint with and without compression and compare the transferred bytes. The difference is usually dramatic for repetitive text like this.

A real-world example: a JSON API

Let us picture a common case. You build an API that returns a list of products as JSON. Each product has a name, a price, a description and a few tags. With a hundred products, the JSON might be around 80 KB of text. JSON is full of repeated keys like "name" and "price" on every item, so it compresses beautifully.

After turning on compression, that same response might travel as only 10 to 15 KB over the wire. The browser still receives the full 80 KB after unpacking, so your front-end code does not change at all. Nothing in your GET /products endpoint or your GET /products/{id} endpoint needs editing. The squeezing happens automatically inside the middleware. This is why compression is such a popular, low-effort win: you change a couple of lines in Program.cs and every text response across your whole app gets smaller.

One more friendly tip: compression and caching work well together. If you also cache responses, the cached copy can be stored already compressed, so repeat visitors get a fast, small response without the server squeezing it again. The two features are good teammates.

Common mistakes to avoid

A few traps catch beginners. Here are the ones to watch for.

  • Calling UseResponseCompression too late in the pipeline, so nothing gets squeezed.
  • Forgetting AddResponseCompression, so the middleware has no service to use.
  • Trying to compress images or videos, which only wastes CPU.
  • Compressing both in Nginx and in the app, doing the work twice.
  • Expecting tiny responses to shrink. Very small bodies may not be worth compressing, and the savings are small.

Keep these in mind and your setup will be smooth.

Quick recap

  • Response compression squeezes text responses so they travel faster and use less data, like a vacuum bag for your data.
  • The browser and server agree on a format using the Accept-Encoding and Content-Encoding headers.
  • ASP.NET Core supports Brotli and Gzip out of the box, and prefers Brotli when the browser supports it.
  • Switch it on with AddResponseCompression plus UseResponseCompression, and place the middleware early in the pipeline.
  • Pick a level: Fastest, Optimal, or SmallestSize. Optimal is a friendly default.
  • Only compress text-like content. Leave images, video and archives alone.
  • EnableForHttps is off by default because of CRIME and BREACH risks. Turn it on for normal public content.
  • A reverse proxy like Nginx or IIS can compress instead of your app, and is often faster. Compress in one place, not two.

References and further reading

Related Posts