Skip to main content
emnode
Site Reliability

Use deployment slots to de-risk App Service releases

One capability for every web app you deploy often: stage a release in a warmed-up slot, validate it against production settings, and swap it into production with no cold start and an instant rollback, so a frequent deployment cadence stops meaning frequent downtime.

14 min·10 sections·AZURE

Last reviewed

De-risking App Service releases: the basics

What does a risky App Service deployment actually look like?

When you deploy straight to the production slot of an Azure App Service web app, the new build lands on the same instances that are serving live traffic. The app domain recycles, the runtime restarts, and the first requests after the deploy hit a cold process that still has to JIT-compile, warm its caches and open its connections. For an app that you ship to once a quarter that is a tolerable blip. For an app that you ship to several times a week it is a recurring window where users see slow responses, timeouts or errors, and where a bad build is already live before anyone notices it is bad.

A deployment slot turns that one risky step into two safe ones. A slot is a fully featured, separately addressable instance of the same app, running on the same App Service plan. You deploy the new build to the slot, let it start and warm up while it serves zero production traffic, validate it on its own hostname, and then swap. The swap is not a redeploy: App Service warms the slot against production configuration, then exchanges the routing between the two slots so the already-running, already-warm instances become production. Because nothing cold-starts at the moment of cutover, the swap is effectively zero-downtime, and if the new build misbehaves you swap back to recover the previous one immediately.

Azure Advisor surfaces this as the reliability recommendation 'Use deployment slots for your App Service resource'. It fires when Advisor sees an app being deployed repeatedly, several times in a week, because that cadence is exactly where deploying in place turns into recurring user-visible impact. The recommendation has a prerequisite: slots are available on the Standard, Premium and Isolated tiers, so an app on Basic or Free has to move up a tier before it can use them. The work this lesson describes is to identify the apps you deploy often, give them a staging slot, and make swap-with-warmup the normal way a release reaches production.

In this lesson you will learn how Azure App Service deployment slots work, why the swap-with-warmup is effectively zero-downtime, how to find the apps where Advisor recommends slots and add one safely, and how to make staged releases the default rather than the exception. You will also see the sharp edges: slot-specific settings that must not follow the swap, the tier prerequisite, and the Linux and container limitation on auto-swap.

Fun fact

The swap that is really a routing change

It is easy to assume a slot swap copies your new build onto the production instances, but that is not what happens. The instances running your staging slot are already live and already warm; the swap simply exchanges which slot the production hostname points at, after App Service has applied production configuration to the staging instances and pinged them to confirm they respond. That is why the swap is effectively instant and why swapping back to recover a bad release is just as fast: the previous version is still running on the instances that were production a moment ago, waiting to be pointed at again. The cutover is a routing change, not a deployment.

Finding the apps that deploy in place too often

Priya is the platform engineer at a SaaS company whose checkout and account services ship multiple times a week. Azure Advisor has raised 'Use deployment slots for your App Service resource' against three apps, and the team has started noticing a brief spike of slow requests in their dashboards right after each deploy.

Before adding slots everywhere, Priya wants to see which apps are even eligible: slots need the Standard tier or higher, so the first job is to separate the apps that can take a slot today from the ones that need a tier bump first.

List your web apps with the App Service plan tier they run on. Apps below Standard cannot use slots until they move up.

$ az webapp list --query "[].{name:name, group:resourceGroup, tier:sku}" -o table
Name Group Tier
--------------- ------------ --------
checkout-prod shop-rg Standard
account-prod shop-rg Premium
promos-prod shop-rg Basic
# checkout and account can take a slot now. promos must move to Standard first.

Apps on Standard or above can take a staging slot with no extra compute cost. An app on Basic or Free needs a tier upgrade before slots are available, which is the one real cost in this capability.

How a swap-with-warmup actually reaches zero downtimedeep dive

A deployment slot is a separate instance of your app that shares the production app's App Service plan. It has its own hostname, its own configuration, and it can run a different build, but it draws on the same pool of compute you already pay for. When you swap, App Service does not copy code. It first applies the production slot's configuration to the instances running in the staging slot, including any settings marked as not slot-specific, then warms those instances by sending an HTTP request to them and waiting for a healthy response, and only then exchanges the routing so the warmed staging instances become production. Because the instances are already started and warm at the moment of cutover, requests never hit a cold process.

You control the warm-up with app settings on the slot. 'WEBSITE_SWAP_WARMUP_PING_PATH' sets the path App Service pings to confirm the slot is ready, for example '/health', and 'WEBSITE_SWAP_WARMUP_PING_STATUSES' lists the HTTP status codes that count as healthy, for example '200,202'. If the warm-up ping does not return a listed status, the swap is stopped before any traffic moves, so a build that fails its own health check never becomes production. Some configuration is deliberately slot-specific and does not move with a swap: settings and connection strings marked as a deployment-slot setting stay put, which is how a slot keeps its own staging database or staging credentials while still inheriting the rest of production's config.

Two operational details matter. First, you can preview a swap: 'swap --action preview' applies production config to the staging slot and pauses, so you can run final checks against the soon-to-be-production instances before completing with a second command, or cancel with a reset. Second, auto-swap can make this automatic, swapping a slot into production as soon as a deploy to it warms up successfully, but auto-swap is not supported on Linux apps or Web App for Containers, so those keep an explicit swap step in the pipeline.

What is the impact of deploying straight to production?

The direct impact is user-visible downtime on every release. Deploying in place recycles the app, so the first requests after each deploy hit a cold runtime, and for an app shipped several times a week that is a recurring window of slow responses, timeouts and errors. The faster the team ships, the more of these windows there are. An in-place deploy also makes the new build live the instant it lands, so a regression is in front of customers before anyone has validated it.

The second-order impact is recovery time. Without a slot, rolling back a bad release means redeploying the previous build, which is itself a cold deploy that takes minutes and carries its own risk, all under the pressure of a live incident. With a slot, the previous version is still running on the instances that were production moments ago, so recovery is a single swap-back measured in seconds. The difference between those two recovery paths is the difference between a brief blip and a prolonged outage during the worst possible moment.

There is a knock-on effect on release behaviour too. When every deploy is risky, teams batch changes and ship less often to limit exposure, which makes each release larger and riskier still. When releases are de-risked with slots, teams can ship small changes frequently and safely, which is the healthier pattern. Advisor raises the recommendation precisely on the apps with a high deploy cadence, because those are the ones where deploying in place does the most damage and where slots pay back fastest.

How do you add deployment slots safely?

Treat this as turning a risky one-step deploy into a safe two-step release, app by app. The order matters: confirm the tier, get the slot-specific settings right before the first swap, and only then make swap-with-warmup the default, so you do not move staging credentials into production by accident.

1. Confirm the tier and add a staging slot

Slots require Standard, Premium or Isolated. For apps already there, add a slot at no extra compute cost; for apps below, decide whether the deploy cadence justifies a tier upgrade first. Create one staging slot per app and have your pipeline deploy to the slot rather than to production.

2. Mark the settings that must not follow the swap

Decide which app settings and connection strings are slot-specific, the staging database, staging API keys, anything that must differ from production, and mark them as deployment-slot settings so they stay put when you swap. Getting this right before the first swap is what stops a swap from pushing staging credentials into production or pulling production secrets into staging.

3. Validate in staging, then swap with warm-up

Set a warm-up ping path and the status codes that count as healthy so a build that fails its own health check is never swapped in. Run smoke tests against the staging hostname, optionally use a preview swap to check against production config first, then complete the swap. Keep the previous version on the now-staging slot so a swap-back is your instant rollback.

4. Make staged release the default

Bake the slot into the app's infrastructure as code so it exists by design, not by hand, and wire the swap into the deployment pipeline so every release goes via staging. For Windows apps you can enable auto-swap; for Linux and container apps, keep an explicit swap step, since auto-swap is not supported there.

# Add a staging slot to an app already on Standard or above (no extra compute cost),
# set the warm-up health check, deploy to the slot, validate, then swap.
GROUP=shop-rg
APP=checkout-prod

# 1. Create the staging slot.
az webapp deployment slot create \
  --resource-group "$GROUP" --name "$APP" --slot staging

# 2. Make the warm-up ping a real health check, and mark it slot-specific so it
#    does not follow the swap. --slot-settings keeps these settings on the slot.
az webapp config appsettings set \
  --resource-group "$GROUP" --name "$APP" --slot staging \
  --slot-settings WEBSITE_SWAP_WARMUP_PING_PATH=/health \
                  WEBSITE_SWAP_WARMUP_PING_STATUSES=200,202

# 3. (Your pipeline deploys the new build to the staging slot here, then runs
#    smoke tests against https://$APP-staging.azurewebsites.net.)

# 4. Optional: preview the swap (applies production config to staging, then pauses).
az webapp deployment slot swap \
  --resource-group "$GROUP" --name "$APP" \
  --slot staging --target-slot production --action preview

# 5. Complete the swap (zero-downtime cutover). To undo a bad release, run the
#    same swap again to put the previous version back in seconds.
az webapp deployment slot swap \
  --resource-group "$GROUP" --name "$APP" \
  --slot staging --target-slot production --action swap

# ---------------------------------------------------------------------------
# Define the slot in infrastructure as code so it exists by design, not by hand.
# The Bicep below declares the production app and its staging slot on the same
# plan, which must be Standard ('S1') or higher for slots to be available.
# ---------------------------------------------------------------------------
# param location string = resourceGroup().location
#
# resource plan 'Microsoft.Web/serverfarms@2024-04-01' = {
#   name: 'checkout-plan'
#   location: location
#   sku: {
#     name: 'S1'
#     tier: 'Standard'
#   }
# }
#
# resource app 'Microsoft.Web/sites@2024-04-01' = {
#   name: 'checkout-prod'
#   location: location
#   properties: {
#     serverFarmId: plan.id
#     httpsOnly: true
#   }
# }
#
# resource stagingSlot 'Microsoft.Web/sites/slots@2024-04-01' = {
#   parent: app
#   name: 'staging'
#   location: location
#   properties: {
#     serverFarmId: plan.id
#     httpsOnly: true
#     siteConfig: {
#       // Warm-up health gate: the swap is blocked unless this path responds.
#       appSettings: [
#         {
#           name: 'WEBSITE_SWAP_WARMUP_PING_PATH'
#           value: '/health'
#         }
#         {
#           name: 'WEBSITE_SWAP_WARMUP_PING_STATUSES'
#           value: '200,202'
#         }
#       ]
#     }
#   }
# }

Quick quiz

Question 1 of 5

Azure Advisor raises 'Use deployment slots for your App Service resource' on an app you deploy several times a week. Why does the cadence matter?

You can now treat a frequent App Service deploy cadence as a controllable risk rather than a recurring outage: confirm the tier, add a staging slot at no compute cost on Standard or above, mark the genuinely slot-specific settings so they do not follow the swap, gate the swap on a real warm-up health check, and make swap-with-warmup the default way releases reach production, with a single swap-back as your instant rollback.

Back to the library