Modern APIs rarely move small amounts of data.
A single response can contain thousands of JSON objects, large metadata structures, search results, configuration documents, or generated reports. Sending that data uncompressed increases bandwidth consumption and can increase network latency.
HTTP compression addresses this by reducing the size of response payloads before they travel across the network.
In ASP.NET Core, response compression can be enabled with middleware:
builder.Services.AddResponseCompression();
var app = builder.Build();
app.UseResponseCompression();
The interesting question is not whether compression works.
The real question is:
Which compression algorithm provides the best balance between response size, CPU consumption, latency, and throughput for a particular API?
Brotli and Gzip can produce very different results depending on the payload, compression level, CPU capacity, and network conditions.
This makes HTTP compression an excellent candidate for benchmarking rather than configuration by assumption.
Why HTTP Compression Matters
Consider an API returning a 500 KB JSON response.
Without compression:
Application
↓
500 KB
↓
Network
↓
Client
With compression:
Application
↓
500 KB JSON
↓
Compressed
↓
150 KB
↓
Network
↓
Client
↓
Decompressed
The server performs additional CPU work, but the network transfers substantially less data.
That creates a fundamental trade-off:
Compression
↓
Smaller payload
↓
Less network transfer
But
Compression
↓
More CPU work
The optimal configuration depends on which resource is the bottleneck.
Compression Algorithms in ASP.NET Core
ASP.NET Core response compression supports common HTTP compression formats including:
Clients communicate their supported algorithms using the Accept-Encoding header.
For example:
GET /api/products HTTP/1.1
Accept-Encoding: br, gzip
The server can then select an appropriate encoding.
The response contains:
Content-Encoding: br
or:
Content-Encoding: gzip
If compression is not appropriate, the server can return the response without compression.
Configure Brotli and Gzip
A typical ASP.NET Core configuration can enable both providers:
using Microsoft.AspNetCore.ResponseCompression;
builder.Services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
options.Providers.Add<BrotliCompressionProvider>();
options.Providers.Add<GzipCompressionProvider>();
});
Compression levels can also be configured:
builder.Services.Configure<BrotliCompressionProviderOptions>(options =>
{
options.Level = System.IO.Compression.CompressionLevel.Fastest;
});
builder.Services.Configure<GzipCompressionProviderOptions>(options =>
{
options.Level = System.IO.Compression.CompressionLevel.Fastest;
});
The exact compression level should be selected through measurement.
Faster compression is not automatically better, and maximum compression is not automatically better either.
Compression Level Creates Another Trade-Off
Compression algorithms generally provide different levels of CPU usage and compression ratio.
Conceptually:
Fastest
↓
More CPU efficiency
↓
Larger response
Balanced
↓
Moderate CPU
↓
Moderate response size
Smallest
↓
More CPU
↓
Smaller response
For a CPU-bound API, an aggressive compression level may hurt throughput.
For a bandwidth-constrained service, the additional CPU cost may be worthwhile.
What Should Be Benchmarked?
A useful benchmark should measure at least four dimensions:
Compressed payload size
Compression CPU time
End-to-end latency
Requests per second
You can represent the experiment as:
Payload
↓
Algorithm
↓
Compression
↓
Response
↓
Measure
┌───────────────┐
│ Size │
│ CPU │
│ Latency │
│ Throughput │
└───────────────┘
Do not optimize only for payload size.
A 5% smaller response is not necessarily valuable if it requires significantly more CPU.
Use Realistic API Payloads
A benchmark using:
"hello world"
does not tell you much about a production API.
Use representative responses such as:
{
"items": [
{
"id": 1001,
"name": "Product A",
"description": "Product description...",
"category": "Technology",
"metadata": {
"region": "US",
"status": "active"
}
}
]
}
Large JSON documents are particularly useful because real APIs often contain repeated property names and similar structural patterns.
Also include payloads with different characteristics.
Highly Repetitive JSON
Large compression opportunity
Random or High-Entropy Data
Limited compression opportunity
Large Text
Usually highly compressible
Already Compressed Binary Data
Often little benefit
This prevents the benchmark from producing conclusions that apply only to one type of response.
Build a Compression Benchmark Dataset
A practical test suite might contain:
| Dataset | Approx. Size | Content |
|---|
| Small JSON | 5 KB | API metadata |
| Medium JSON | 100 KB | Search results |
| Large JSON | 1 MB | Reporting API |
| Large text | 1 MB | Documentation |
| Binary | 1 MB | Image/file data |
This allows the benchmark to answer a more useful question:
How does compression behave across the payload sizes my API actually serves?
Measure Compression Ratio
One of the simplest metrics is compression ratio:
Compression Ratio =
Compressed Size / Original Size
For example:
Original: 500 KB
Compressed: 150 KB
Ratio = 150 / 500
= 0.30
That means the compressed response is approximately 30% of the original size.
You can also report bandwidth reduction:
Bandwidth Reduction =
1 - (Compressed Size / Original Size)
In this example:
1 - 0.30
= 70%
This is often easier to communicate to infrastructure teams.
Measure Compression CPU Time
Compression consumes CPU.
A benchmark should therefore record the time required to generate the compressed payload.
For example:
Algorithm Payload Compression Time
Brotli 1 MB ...
Gzip 1 MB ...
The actual numbers depend on:
CPU architecture
Runtime version
Compression level
Payload characteristics
Operating system
Memory pressure
Never treat benchmark results from one machine as universal.
Benchmark Brotli and Gzip Separately
A useful experiment can use a reusable payload:
private static readonly byte[] Payload =
Encoding.UTF8.GetBytes(LargeJsonPayload);
Then benchmark each algorithm independently.
The benchmark should ensure that the payload and execution environment remain identical.
Conceptually:
Same payload
|
+---- Brotli
|
+---- Gzip
The only variable should be the compression configuration.
Benchmark Different Compression Levels
For Brotli, test multiple levels rather than selecting one level and declaring it optimal.
For example:
var options = new BrotliCompressionProviderOptions
{
Level = CompressionLevel.Fastest
};
Then compare the appropriate supported levels for your workload.
The experiment should produce something similar to:
| Algorithm | Level | Size | CPU | Latency |
|---|
| Brotli | Fast | ... | ... | ... |
| Brotli | Balanced | ... | ... | ... |
| Brotli | Smallest | ... | ... | ... |
| Gzip | Fast | ... | ... | ... |
| Gzip | Balanced | ... | ... | ... |
The point is not to find a universally best setting.
It is to identify the best point on your application's performance curve.
Benchmark the Complete ASP.NET Core Pipeline
A pure compression benchmark is useful, but it does not represent an entire API request.
A real request includes:
HTTP Request
↓
Routing
↓
Authentication
↓
Controller/Endpoint
↓
Serialization
↓
Compression
↓
Network
For realistic results, benchmark the complete API.
For example:
app.MapGet("/api/products", () =>
{
return Results.Ok(GetLargeProductCollection());
});
Then invoke the endpoint with:
Accept-Encoding: br
and:
Accept-Encoding: gzip
This captures serialization and middleware overhead in addition to compression.
Compression and JSON Serialization
Compression happens after the application produces the response representation.
That means serialization performance still matters.
Consider:
Database
↓
Objects
↓
JSON Serialization
↓
Compression
↓
HTTP Response
If JSON serialization takes 20 ms and compression takes 2 ms, reducing compression to 1 ms may not materially improve total latency.
Similarly, if compression takes 15 ms on a large response, optimization may be worthwhile.
Always measure the entire request path.
Test HTTPS Traffic
Compression is frequently used over HTTPS.
ASP.NET Core allows response compression to be enabled for HTTPS:
builder.Services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
});
However, enabling compression indiscriminately requires careful security consideration.
Compression should primarily target appropriate response content and should not be treated as a universal setting for every response.
Avoid Compressing Everything
Some payloads do not benefit significantly from HTTP compression.
Examples include:
Compressing them again can consume CPU while providing little size reduction.
A useful rule is:
Already compressed?
↓
Usually skip HTTP compression
Content Type Matters
Compression is most useful for text-based content such as:
JSON
XML
HTML
CSS
JavaScript
Plain text
ASP.NET Core response compression uses MIME types to determine which responses should be compressed.
You can configure additional MIME types when required:
builder.Services.AddResponseCompression(options =>
{
options.MimeTypes = new[]
{
"application/json",
"application/problem+json",
"text/plain"
};
});
Do not simply add every content type.
Verify that the selected data actually benefits from compression.
Small Responses May Not Be Worth Compressing
Compression has overhead.
For a response of only a few hundred bytes:
Compression CPU
+
Compression metadata
may not justify the small bandwidth savings.
A useful benchmark should therefore include small responses.
For example:
1 KB
10 KB
100 KB
1 MB
5 MB
You may find that compression becomes increasingly valuable as payload size increases.
Network Conditions Change the Result
CPU benchmarks alone can produce the wrong conclusion.
Imagine:
Brotli:
Smaller payload
Higher CPU
and:
Gzip:
Larger payload
Lower CPU
On a fast internal network, Gzip may provide better overall latency.
On a slow mobile connection, Brotli may win because transferring fewer bytes matters more.
Therefore, test under representative network conditions.
Calculate End-to-End Latency
A useful simplified model is:
Total Latency =
Application Processing
+
Serialization
+
Compression
+
Network Transfer
+
Client Processing
Compression changes two parts of this equation:
Compression
↓
CPU time increases
Payload size
↓
Network transfer decreases
The correct algorithm is the one that improves the total result for your workload.
Benchmark Throughput
A high-traffic API also needs throughput testing.
Measure:
Requests per second
while maintaining a realistic concurrency level.
For example:
10 concurrent requests
50 concurrent requests
100 concurrent requests
500 concurrent requests
Watch for:
CPU saturation
Memory growth
Increased latency
Garbage collection
Queueing
Reduced throughput
An algorithm that performs well for one request may behave differently under sustained load.
Watch CPU Utilization
Compression can become CPU-bound under high traffic.
Suppose:
Without compression
CPU: 45%
With compression
CPU: 82%
The bandwidth savings may be valuable, but the application has much less CPU headroom.
This matters when the service is already close to its scaling threshold.
Compression can therefore affect infrastructure costs as well as application performance.
Use Response Size as a Scaling Metric
A useful operational metric is total compressed bytes sent.
For example:
Requests/sec: 1,000
Average response: 200 KB
Without compression:
≈ 200 MB/sec
If compression reduces the average response to 60 KB:
≈ 60 MB/sec
That difference can materially affect network utilization.
The exact numbers should always be calculated from your actual traffic.
Common Mistakes
Benchmarking Only Compression Ratio
A smaller response does not automatically mean a faster API.
Using Tiny Test Payloads
Compression behavior becomes more meaningful with realistic response sizes.
Ignoring CPU
Compression trades network bandwidth for CPU work.
Compressing Already-Compressed Data
This can waste CPU without meaningful bandwidth savings.
Testing Only One Compression Level
Different levels can produce different CPU/size trade-offs.
Ignoring Network Conditions
A compression strategy that works well on a datacenter network may behave differently for geographically distributed clients.
Benchmarking Only the Compression Library
The API also spends time on routing, business logic, serialization, and other middleware.
Best Practices
Benchmark Brotli and Gzip using identical payloads.
Test multiple payload sizes.
Measure response size and compression ratio.
Measure CPU and memory consumption.
Include end-to-end API latency.
Test multiple compression levels.
Measure throughput under realistic concurrency.
Avoid compressing already-compressed formats.
Enable compression only for content types that benefit.
Test representative network conditions.
Compare compression overhead against serialization and application processing time.
Re-run benchmarks after major .NET runtime upgrades.
Monitor CPU and network utilization in production.
Select compression settings based on workload rather than generic recommendations.
Frequently Asked Questions
Is Brotli always better than Gzip?
No. Brotli can provide strong compression for many text workloads, but the best choice depends on payload, compression level, CPU capacity, and network conditions.
Does compression always improve API latency?
No. Compression adds CPU work. If the network is already fast and the response is small, compression may provide little benefit.
Should JSON APIs always enable compression?
Large JSON responses are often good candidates, but the decision should be based on measurements and response size.
Should images be compressed by ASP.NET Core?
Usually not when they are already encoded in compressed formats such as JPEG or PNG. Recompressing them often provides little additional benefit.
What is the most important benchmark metric?
There is no single metric. The useful combination is compressed size, CPU cost, end-to-end latency, and throughput.
Should production use the highest compression level?
Not automatically. Higher compression can increase CPU consumption. Benchmark the workload and choose the level that provides an acceptable size/CPU trade-off.
Conclusion
HTTP compression is a classic example of an optimization that involves a trade-off rather than a simple yes-or-no decision.
The fundamental relationship is:
More Compression
↓
Smaller Payload
↓
Less Network Traffic
But
More Compression
↓
More CPU Work
For ASP.NET Core APIs, Brotli and Gzip should therefore be evaluated against realistic workloads rather than selected purely from generic benchmarks.
A useful experiment should measure:
Payload Size
↓
Compression Algorithm
↓
Compression Level
↓
CPU
↓
Latency
↓
Throughput
↓
Network Transfer
The best configuration is the one that improves the overall behavior of the application.
For a bandwidth-constrained API, stronger compression may be worth additional CPU usage. For a CPU-bound internal service, a faster compression level may be the better choice.
The important engineering principle is simple: HTTP compression should be treated as a measurable performance trade-off, not a default optimization that can be evaluated using payload size alone.