Updated October 2026: added the built-in IIS settings that solve most cold starts (AlwaysRunning, preload, Application Initialization), PowerShell and appcmd commands for each, ASP.NET Core notes, and an improved warm-up script.
The Problem: Idle IIS Sites Are Slow
On IIS, a site that hasn't had traffic for a while goes cold. By default an application pool's worker process (w3wp.exe) shuts down after 20 minutes of inactivity, and it is also recycled every 29 hours. The next visitor waits while IIS starts a new process and your app loads, JIT-compiles and warms its caches. For an ASP.NET app that can mean several seconds, which hurts users and search crawlers alike.
Quick Answer: The IIS Keep Alive Settings
| Setting | Where | Default | Set to |
|---|---|---|---|
| Start Mode | Application pool > Advanced Settings | OnDemand | AlwaysRunning |
| Idle Time-out (minutes) | Application pool > Advanced Settings > Process Model | 20 | 0 (never) |
| Preload Enabled | Site > Advanced Settings | False | True |
| Regular Time Interval (recycling) | Application pool > Recycling | 1740 minutes | 0, plus a fixed off-peak time |
| Application Initialization | Server role feature | Not installed | Installed |
Together these keep the worker process running, start your app as soon as IIS starts (after a reboot or recycle), and move recycles to a quiet time.
Option 1: Configure IIS (Recommended)
With PowerShell
# Run in an elevated Windows PowerShell 5.1 window (WebAdministration module)
Import-Module WebAdministration
$pool = "MySiteAppPool"
$site = "MySite"
# 1) Install Application Initialization (needed for preload / warm-up)
Install-WindowsFeature Web-AppInit # Windows Server
# Enable-WindowsOptionalFeature -Online -FeatureName IIS-ApplicationInit # Windows 10/11
# 2) Start the worker process as soon as IIS starts, and never shut it down when idle
Set-ItemProperty "IIS:\AppPools\$pool" -Name startMode -Value AlwaysRunning
Set-ItemProperty "IIS:\AppPools\$pool" -Name processModel.idleTimeout -Value ([TimeSpan]::Zero)
# 3) Preload the site so the app is loaded before the first request arrives
Set-ItemProperty "IIS:\Sites\$site" -Name applicationDefaults.preloadEnabled -Value $true
# 4) Recycle at a quiet fixed time instead of every 29 hours (1740 minutes)
Set-ItemProperty "IIS:\AppPools\$pool" -Name recycling.periodicRestart.time -Value ([TimeSpan]::Zero)
Clear-ItemProperty "IIS:\AppPools\$pool" -Name recycling.periodicRestart.schedule
New-ItemProperty "IIS:\AppPools\$pool" -Name recycling.periodicRestart.schedule -Value @{value = "04:00:00"}
With appcmd
%windir%\system32\inetsrv\appcmd set apppool "MySiteAppPool" /startMode:AlwaysRunning /processModel.idleTimeout:00:00:00
%windir%\system32\inetsrv\appcmd set site "MySite" /applicationDefaults.preloadEnabled:true
With IIS Manager
- Application Pools > select your pool > Advanced Settings...: set Start Mode to
AlwaysRunningand Idle Time-out (minutes) to0. Under Recycling, set Regular Time Interval to0and add a Specific Time. - Sites > select your site > Advanced Settings...: set Preload Enabled to
True. - In Server Manager, add the role service Web Server > Application Development > Application Initialization.
More background on why the default is 1740 minutes: Scott Forsyth on IIS app pool recycling.
Warm Up Specific Pages
With Application Initialization installed you can list URLs that IIS should request after every start or recycle, which fills caches before real visitors arrive:
<!-- web.config: warm up specific URLs after every start or recycle -->
<configuration>
<system.webServer>
<applicationInitialization doAppInitAfterRestart="true">
<add initializationPage="/" />
<add initializationPage="/blog" />
</applicationInitialization>
</system.webServer>
</configuration>
ASP.NET Core on IIS
- In-process hosting (the default since ASP.NET Core 3.0) runs your app inside
w3wp.exe, so the app pool settings above apply directly. With AlwaysRunning + Preload Enabled + Application Initialization, the app starts right after IIS does. - Out-of-process hosting runs Kestrel in a separate
dotnet.exeor.exeprocess that the ASP.NET Core Module starts on the first request. Preload and Application Initialization still trigger that first request for you. - The app pool's .NET CLR version should be No Managed Code for ASP.NET Core.
- Recycling an ASP.NET Core app pool also clears in-memory caches, so a fixed off-peak recycle time is kinder than a rolling 29-hour interval.
Option 2: A Warm-Up (Ping) Task
The settings above remove almost all cold starts. A scheduled warm-up request is still useful as a belt-and-braces check, for sites where you can't change server settings, or to keep page-level caches fresh. This script requests the home page of every started IIS site, using each site's own host-name bindings:
# C:\scripts\keepalive.ps1 - request the home page of every started IIS site
Import-Module IISAdministration
$urls = Get-IISSite |
Where-Object { $_.State -eq 'Started' } |
ForEach-Object {
foreach ($binding in $_.Bindings) {
if ($binding.Protocol -in 'http', 'https' -and $binding.Host) {
"$($binding.Protocol)://$($binding.Host)/"
}
}
} |
Sort-Object -Unique
foreach ($url in $urls) {
try {
$response = Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 60
Write-Output "$url $($response.StatusCode)"
}
catch {
Write-Output "$url FAILED: $($_.Exception.Message)"
}
}
Schedule it every 10 minutes as SYSTEM, so it runs in the background whether or not anyone is logged in:
REM Run the warm-up script every 10 minutes as SYSTEM, starting now
schtasks /Create /TN "IIS Keep Alive" /SC MINUTE /MO 10 /RU SYSTEM /RL HIGHEST ^
/TR "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\scripts\keepalive.ps1"
Prefer the GUI? In taskschd.msc, create a task that starts powershell.exe with the arguments -NoProfile -ExecutionPolicy Bypass -File C:\scripts\keepalive.ps1, add a daily trigger that repeats every 10 minutes for a duration of 1 day, and set the account to SYSTEM.
An external uptime monitor that requests your site every few minutes has the same effect, and it also tells you when the site is down.
Frequently Asked Questions
How do I keep an IIS site alive?
Set the application pool's Start Mode to AlwaysRunning and Idle Time-out to 0, set the site's Preload Enabled to True, install the Application Initialization feature, and schedule recycling at a fixed off-peak time.
What does the IIS idle timeout do?
It shuts down the application pool's worker process after that many minutes without requests (20 by default). The next request then has to start the process and load the app again, which is the slow "first hit" people notice.
Is it safe to set Idle Time-out to 0?
Yes for most servers. The trade-off is memory: every pool stays loaded even with no traffic. On a server with dozens of rarely used sites, keep AlwaysRunning for the important ones and leave the defaults for the rest.
Does AlwaysRunning work without Application Initialization?
AlwaysRunning starts the worker process, but your application code only loads when it gets a request. Application Initialization with Preload Enabled sends that first request for you, so the app is ready before a real visitor arrives.
Summary
Most slow first requests on IIS come from two defaults: a 20-minute idle timeout and a 29-hour recycle. Turn on AlwaysRunning, Preload Enabled and Application Initialization, schedule the recycle for a quiet time, and use a small warm-up task as a safety net.
Related: automating IIS log cleanup and fixing locked files when deploying to IIS.

