Skip to content

App Service Deployment Slots Support - Phase 1 #6526

@puicchan

Description

@puicchan

Summary

Add support for deploying to Azure App Service deployment slots to enable zero-downtime deployments with staging validation before production promotion.

Problem

Currently, azd deploy deploys directly to the production App Service. Teams need to:

  • Deploy to a staging slot for validation
  • Promote staging to production with zero downtime
  • Rollback quickly if issues are detected

This workflow is a standard best practice for production deployments but requires manual intervention outside of azd.

Proposed Solution

New CLI Commands

Deploy to Slot

azd deploy <service> --to <slot-name>
azd deploy <service> --from-package <package-path> --to <slot-name>

Examples:

azd deploy web --to staging                                  # deploy to staging slot
azd deploy web --from-package ./dist/web.zip --to staging  # deploy package to staging

Promote to Production (Traffic Shift)

azd deploy <service> --traffic <slot-name>:100

Examples:

azd deploy web --traffic staging:100      # promote staging to production (triggers swap)
azd deploy web --traffic production:100   # rollback (swap back)

Interactive confirmation before swap:

Ready to shift 100% traffic to staging (this will swap slots):
  Current production:
    Version: azd-deploy-20260107-1015
  Staging (will become production):
    Version: azd-deploy-20260107-1210

Proceed with traffic shift? (Y/n)

Check Deployment Status

azd deploy <service> --status

Shows current version/URL for each slot (production, staging, etc.).

User Workflow

# 1. Deploy to staging
azd deploy web --to staging

# 2. Test staging
# ... run tests against staging URL ...

# 3. Promote to production
azd deploy web --traffic staging:100

# 4. Rollback if needed
azd deploy web --traffic production:100

Prerequisites (User Setup)

Users must manually add slot infrastructure:

Bicep with AVM module:

module stagingSlot 'br/public:avm/res/web/site/slot:0.2.0' = { ... }

output SERVICE_WEB_STAGING_URI string = 'https://${stagingSlot.outputs.name}.azurewebsites.net'
output SERVICE_WEB_STAGING_NAME string = stagingSlot.outputs.name

Requirements:

  • App Service Plan must be Standard S1+ or Premium tier (Basic/Free don't support slots)
  • Slot infrastructure outputs must follow naming convention: SERVICE_{SERVICENAME}_{SLOTNAME}_URI

Optional azure.yaml default:

services:
  web:
    project: .
    language: py
    host: appservice
    deployment:
      slot: staging  # default slot when using --to without argument

Implementation Considerations

1. Infrastructure Detection

  • Read azure.yaml to identify services and optional default slot (deployment.slot)
  • Read azd provision outputs to detect which slots exist in infrastructure (don't parse IaC files)
  • Required outputs: SERVICE_{SERVICENAME}_{SLOTNAME}_URI, SERVICE_{SERVICENAME}_{SLOTNAME}_NAME
  • Works with any IaC tool (Bicep, Terraform)
  • Clear error if outputs missing with guidance on adding slot infrastructure

2. Deployment Type Detection

  • Only support code-based App Service deployments (zip deploy, run from package)
  • Error if user attempts slot operations on Web App for Containers: "Deployment slots for containerized App Services are not yet supported. Use Azure Container Apps for container-based blue/green deployments."

3. Traffic Management (Swap)

  • For App Service: --traffic <slot>:100 triggers atomic slot swap
  • Only 0% or 100% supported (binary traffic model)
  • Interactive confirmation before swap with version info
  • Track deployment version in app settings (AZD_DEPLOYMENT_VERSION) for visibility

4. Version Tracking

Store deployment metadata in slot app settings for auditing:

  • CI/CD: Extract from environment variables (commit hash, branch, build number)
  • Local dev: Generate identifier azd-deploy-YYYYMMDD-HHMM
  • Mark as slot-specific (sticky) so version stays with slot during swap

5. Configuration Management

  • Phase 1: All slots share same configuration from azd environment (.azure/<env-name>/.env)
  • For slot-specific config needs: use multiple azd environments (Pattern 2)
  • Future (Phase 3): Native slot-specific configuration support

6. Error Handling

  • Clear error if slot doesn't exist
  • Clear error if App Service Plan SKU doesn't support slots
  • Graceful handling if swap fails (Azure API errors)
  • Best-effort warning if deployment appears in progress

7. User Experience

  • Show clear progress during traffic shift
  • Display slot URLs after deployment
  • Warnings before destructive operations
  • Show version info before/after traffic shifts
  • Maintain backward compatibility (no flags = deploy to production)

8. Telemetry (Required)

Track usage metrics to inform Phase 2-4 decisions:

  • deploy.to - deployment to slot
  • deploy.traffic - traffic shift operation
  • deploy.status - status check
  • Success/failure rates, operation latency, slot names used

9. Known Limitations

  • No concurrent operation protection (document to avoid simultaneous operations)
  • Shared configuration across slots (until Phase 3)
  • Code-based App Service only (no container support)

Design Principles

  1. Generic interface: Use --to flag that will extend to Container Apps in Phase 2
  2. Leverage existing features: Use existing --from-package for artifact promotion
  3. Output-based detection: Read provision outputs, not IaC files
  4. Backward compatible: No breaking changes; existing behavior unchanged without flags
  5. Infrastructure-agnostic: Works with Bicep, Terraform, ARM

Success Criteria

  1. Users can deploy to staging slot with single command
  2. Traffic shift operation completes in < 10 seconds
  3. Zero downtime during traffic shift
  4. Clear error messages guide users to correct configuration
  5. 90% of users successfully deploy with slots on first attempt

Out of Scope (Future Phases)

  • Phase 2: Container Apps revision support with same --to interface
  • Phase 3: Auto-provision slots, slot-specific configuration, concurrency protection
  • Phase 4: TBD

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions