0. First principle: measure before tuning
Before touching settings:
- Use: PerfMon, dotnet-counters, dotnet-trace, Failed Request Tracing, IIS logs.
- Track at least:
- Requests/sec
- Avg/95th latency
- CPU %
- RAM / GC pauses
- HTTP errors (4xx/5xx)
- Change one thing at a time and compare.
1. OS & Hardware-level optimizations
These are outside IIS but critical:
- Use modern Windows Server (2019+ ideally) – better HTTP.sys, HTTP/2/3 support, TLS performance, etc.
- Enough CPU & RAM; avoid constant >80% CPU.
- Use SSD/NVMe for web content and logs.
- Network:
- Enable RSS/Receive Side Scaling, offloads (checksum, LSO) if appropriate.
- Make sure NIC drivers are updated.
- Power plan: set to High performance on servers.
- Disable unnecessary background services and scheduled tasks that contend for CPU/IO.
2. IIS application pool tuning
2.1 .NET CLR & pipeline
For ASP.NET Core with ANCM:
- Use No Managed Code in app pool (since Core runs out-of-process) – avoids extra .NET overhead in w3wp.
For classic ASP.NET:
- Use Integrated pipeline mode (not Classic) for better performance & features.
2.2 Recycling
Recycling too often kills warm state and hurts latency:
- Disable time-based recycling (e.g., every 29 hours) unless you have a strong reason.
- Prefer recycling on:
- Specific memory limits (if leak suspected)
- Configuration changes (default)
- Use overlapped recycling and preloading to avoid cold start spikes.
2.3 Idle timeout & start mode
- For high-traffic / critical apps:
- Set Idle Time-out higher or 0 (no timeout).
- Enable AlwaysRunning + Application Initialization so app is always warm.
- For many small sites:
- Keep idle timeout to auto-suspend low-traffic apps to save RAM.
2.4 Queue length & throttling
queueLength(Application pool → Advanced settings):- Increase from default (1000) if you see 503.2 (queue full) and backend is still healthy.
- Consider CPU throttling only when you want fairness between sites; it can also become a bottleneck if set too low.
3. Site & connection-level settings
3.1 Max concurrent connections and limits
- Tune connectionTimeout, maxConnections, and request limits (Request Filtering → maxAllowedContentLength, maxRequestLength).
- Too low → users get 400/413; too high → risk of memory exhaustion during attacks.
3.2 HTTP/2 & TLS
- Enable HTTP/2 where possible – especially for many small static resources.
- Use modern cipher suites and TLS session resumption for lower CPU per SSL handshake.
3.3 Keep-alive & pipelining
- Keep-alive enabled to reuse TCP connections.
- Keep-alive timeout: balance between:
- High enough to reuse connections
- Low enough to avoid too many idle connections consuming memory.
4. Caching (the big win)
4.1 Static content caching
- Enable kernel-mode caching and static file caching:
- Client cache: set long
Cache-Controlheaders (public, max-age=31536000) for versioned static assets (CSS/JS/images with hashes). - IIS Output Cache / HTTP.sys: cache frequently requested static responses in memory.
- Client cache: set long
4.2 Dynamic output caching
For pages whose output doesn’t change per-user:
- Use Output Caching:
- Cache by URL + query string + headers as needed.
- Use proper vary-by configuration (e.g.,
VaryByParam,VaryByHeader).
- For ASP.NET Core:
- Use Response Caching middleware or application-level memory/Redis cache.
- Beware: wrong vary rules can show other users’ data → test carefully.
4.3 Partial caching
- For classic ASP.NET: use fragment caching for expensive controls/user controls.
- At app layer: cache heavy data (e.g., dropdown lists, configs) in memory/Redis so IIS doesn’t call DB every request.
5. Compression & content optimization
5.1 Static compression
- Enable static compression for text content (HTML, JS, CSS, JSON, XML).
- Don’t compress:
- Already compressed formats (JPEG, PNG, MP4, ZIP, etc.).
- Make sure compression cache directory is on fast disk.
5.2 Dynamic compression
- Enable dynamic compression carefully:
- Good for APIs returning JSON/HTML.
- Watch CPU – heavy dynamic compression + high concurrency can become bottleneck.
- Use thresholds (e.g., only compress responses > some size).
5.3 Brotli / newer algorithms
- On newer Windows / reverse proxies: enable Brotli for extra savings, especially on text content (if supported by your stack).
6. Modules, handlers & pipeline trimming
Every extra module = extra work per request.
- For each site:
- Go to Modules and remove what you don’t need:
WebDAV,ASP,ISAPI,CGI, etc., if unused.
- Go to Modules and remove what you don’t need:
- For static-only sites:
- Disable ASP.NET, authentication modules, etc.
- For API-only sites:
- You might not need session state / forms auth / etc.
This reduces CPU per request and speeds up pipeline.
7. Logging & diagnostics tuning
Logging is essential but can slow you down if misconfigured.
- W3C access logs:
- Use separate log directory on fast disk.
- Avoid logging fields you don’t need.
- Roll logs daily or by size.
- Failed Request Tracing (FREB):
- Enable only for troubleshooting specific status codes (e.g., 500, 503).
- Turn off once done.
- Don’t write massive logs from app to disk synchronously; use async logging + batching (Serilog/Seq, ELK, etc.).
8. Request filtering & security (for performance & safety)
Tuning security helps performance by rejecting bad traffic early.
- Request Filtering:
- Limit maximum URL length, headers length, body size.
- Block unwanted file extensions, methods, verbs.
- IP restrictions / WAF:
- Use IPRestrictions to block abusive IPs.
- Use external WAF / reverse proxy (F5, Nginx, Azure App Gateway, Cloudflare) to filter bots/attacks before IIS.
- Authentication:
- Avoid enabling multiple auth schemes unnecessarily (e.g., Windows + Anonymous + Basic).
- Use the lightest authentication compatible with your requirements.
9. Pooling & concurrency strategy
9.1 Web gardens (multiple worker processes in one app pool)
- Generally NOT recommended for ASP.NET / ASP.NET Core apps that rely on in-process state (Session/InMemory cache).
- Use scaling out with multiple servers or load balancer instead.
- Only consider web gardens when:
- Stateless app
- You understand affinity/load-balancer behavior.
9.2 Multiple sites on same server
- Make sure heavy sites don’t starve lightweight ones:
- Separate app pools.
- Use CPU limits or move heavy sites to dedicated server.
10. Content & front-end optimizations (indirect IIS wins)
These don’t change IIS itself, but dramatically reduce its load:
- Use CDN for static assets (images, JS, CSS) → fewer hits to IIS.
- Minify & bundle JS/CSS.
- Use image optimization:
- WebP/AVIF where possible.
- Proper sizing; avoid 4K images for thumbnails.
- Reduce number of HTTP requests (sprites, bundling, HTTP/2 multiplexing).
Less work for IIS = better performance and lower cost.
11. ASP.NET / ASP.NET Core specific tuning (on top of IIS)
- GC mode:
- Use Server GC for high-throughput server apps.
- Thread pool tuning only when necessary (usually defaults are fine).
- Avoid blocking calls (
.Result,.Wait()) on async flows → thread starvation. - Optimize EF Core / DB access:
- Use pooling, compiled queries, proper indexes.
- Cache config & lookups; avoid reading from disk/DB each request.
IIS is only part of the chain; app inefficiencies dominate many real issues.
12. Scaling strategies with IIS
When vertical tuning isn’t enough:
- Scale out using:
- Multiple IIS servers behind a load balancer (hardware / software / cloud LB).
- Use sticky sessions if you rely on in-process session state; otherwise move session state to:
- SQL Server / Redis / distributed cache.
- Use blue–green deployments or slots (e.g., Azure App Service) to avoid downtime during releases.
13. A simple priority checklist (what to do first)
If you want a quick actionable order for a new/slow IIS app:
- Measure (PerfMon + app metrics).
- Enable static & dynamic compression (watch CPU).
- Set caching headers for static content.
- Trim unnecessary IIS modules.
- Configure app pool:
- No Managed Code (for ASP.NET Core).
- Disable frequent recycling.
- Increase queue length if necessary.
- Enable Application Initialization + AlwaysRunning for warm startup.
- Move logs to fast disk, trim logged fields.
- Add CDN for static content if traffic is high.
- Optimize DB calls and app-layer caching.
- If still slow: consider scaling out with load balancer.
I’m a DevOps/SRE/DevSecOps/Cloud Expert passionate about sharing knowledge and experiences. I have worked at Cotocus. I share tech blog at DevOps School, travel stories at Holiday Landmark, stock market tips at Stocks Mantra, health and fitness guidance at My Medic Plus, product reviews at TrueReviewNow , and SEO strategies at Wizbrand.
Do you want to learn Quantum Computing?
Please find my social handles as below;
Rajesh Kumar Personal Website
Rajesh Kumar at YOUTUBE
Rajesh Kumar at INSTAGRAM
Rajesh Kumar at X
Rajesh Kumar at FACEBOOK
Rajesh Kumar at LINKEDIN
Rajesh Kumar at WIZBRAND
Find Trusted Cardiac Hospitals
Compare heart hospitals by city and services — all in one place.
Explore Hospitals
This is a very well-structured checklist for improving .NET application performance — it covers everything from efficient memory usage and asynchronous programming to caching strategies, database optimizations, and better logging practices. The emphasis on identifying bottlenecks using profiling tools, reducing response times, and optimizing resource usage shows a holistic understanding that performance isn’t just about fast code — it’s about optimal design and architecture. For any team working on enterprise-grade .NET applications, following this checklist can lead to measurable improvements in scalability, maintainability, and user-experience. Thanks for sharing such a practical and comprehensive guide.