Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ resource stagingSlot 'Microsoft.Web/sites/slots@2022-09-01' = {
}
```

## Slot Requirements
## Slot Requirements — App Service

| SKU Tier | Slots Supported |
|----------|-----------------|
Expand All @@ -24,6 +24,84 @@ resource stagingSlot 'Microsoft.Web/sites/slots@2022-09-01' = {
| Standard | 5 |
| Premium | 20 |

## Slot Requirements — Azure Functions

> ⚠️ Slot support for Azure Functions varies by OS and hosting plan.

| Hosting Plan | OS | Slots Supported |
|---|---|---|
| Flex Consumption (FC1) | Linux | ❌ 0 |
| Consumption (Y1) | **Windows** | ✅ 1 staging slot |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Y1 also supports the 1 staging slot. We need to decouple the support of slots with our guidance whether to use Y1 or not. While we don't recommend it, if you *need it, it can be done and it has the slot

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in 651b804. The guidance callout now leads with the factual statement ("Windows Consumption Y1 supports 1 staging slot — this is a supported platform capability. If you need it, use it.") and separates that cleanly from the recommendation ("for new projects, prefer Elastic Premium or Dedicated"). The two concerns are now independent.

| Consumption (Y1) | Linux | ❌ 0 |

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linux Consumption also supports slots (1 Slot) but should not be considered in light of deprecation

| Elastic Premium (EP1-EP3) | Windows or Linux | ✅ 20 slots |
| Dedicated (Standard+) | Windows or Linux | ✅ 5–20 slots |

> 💡 **For Azure Functions requiring deployment slots:**
> - **Windows Consumption (Y1) supports 1 staging slot** — this is a supported platform capability.
> If you need it, use it. See the Bicep example below.
> - Recommendation for new projects: prefer **Elastic Premium (EP1+)** (no cold starts, VNet integration)
> or a **Dedicated plan (Standard+)**. Y1 cold starts can affect slot swap warm-up reliability.
> - **Linux Consumption and Flex Consumption do not support deployment slots.**

### Windows Consumption Function App with Staging Slot (Bicep)

```bicep
resource functionAppPlan 'Microsoft.Web/serverfarms@2022-09-01' = {
name: '${resourcePrefix}-funcplan-${uniqueHash}'
location: location
sku: { name: 'Y1', tier: 'Dynamic' }
// No 'reserved: true' — Windows Consumption
}

resource functionApp 'Microsoft.Web/sites@2022-09-01' = {
name: '${resourcePrefix}-${serviceName}-${uniqueHash}'
location: location
kind: 'functionapp' // Windows (no 'linux' suffix)
identity: { type: 'SystemAssigned' }
properties: {
serverFarmId: functionAppPlan.id
httpsOnly: true
siteConfig: {
appSettings: [
{ name: 'WEBSITE_NODE_DEFAULT_VERSION', value: '~20' }
{ name: 'FUNCTIONS_EXTENSION_VERSION', value: '~4' }
{ name: 'FUNCTIONS_WORKER_RUNTIME', value: 'node' }
{ name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING', value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value}' }
{ name: 'WEBSITE_CONTENTSHARE', value: '${toLower(serviceName)}-prod' }
{ name: 'AzureWebJobsStorage', value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value}' }
{ name: 'APPLICATIONINSIGHTS_CONNECTION_STRING', value: applicationInsights.properties.ConnectionString }
]
}
}
}

// Staging slot — only 1 staging slot supported on Consumption
resource stagingSlot 'Microsoft.Web/sites/slots@2022-09-01' = {
parent: functionApp
name: 'staging'
location: location
kind: 'functionapp'
properties: {
serverFarmId: functionAppPlan.id
siteConfig: {
appSettings: [
{ name: 'WEBSITE_NODE_DEFAULT_VERSION', value: '~20' }
{ name: 'FUNCTIONS_EXTENSION_VERSION', value: '~4' }
{ name: 'FUNCTIONS_WORKER_RUNTIME', value: 'node' }
{ name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING', value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value}' }
{ name: 'WEBSITE_CONTENTSHARE', value: '${toLower(serviceName)}-staging' } // MUST differ from production

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{ name: 'AzureWebJobsStorage', value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value}' }
{ name: 'APPLICATIONINSIGHTS_CONNECTION_STRING', value: applicationInsights.properties.ConnectionString }
]
}
}
}
```

> ⚠️ `WEBSITE_CONTENTSHARE` **must be unique per slot** on Windows Consumption — each slot needs its own file share.
> Use slot-sticky settings (via `slotConfigNames`) for `WEBSITE_CONTENTSHARE` and `WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`
> so these values do not swap with production.

## Deployment Flow

1. Deploy to staging slot
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,19 @@ services:

**Use Flex Consumption for new deployments** (all AZD templates default to Flex).

| Plan | Use Case | Scaling | VNET |
|------|----------|---------|------|
| **Flex Consumption** ⭐ | Default for new projects | Auto, pay-per-execution | ✅ |
| Consumption (Y1) | Variable workloads, cost optimization | Auto, scale to zero | ❌ |
| Premium (EP1-EP3) | No cold starts, longer execution | Auto, min instances | ✅ |
| Dedicated | Predictable load, existing App Service | Manual or auto | ✅ |
| Plan | Use Case | Scaling | VNET | Slots |
|------|----------|---------|------|-------|
| **Flex Consumption** ⭐ | Default for new projects | Auto, pay-per-execution | ✅ | ❌ |
| Consumption Windows (Y1) | Legacy/maintenance, Windows-only features | Auto, scale to zero | ❌ | ✅ 1 staging slot |
| Consumption Linux (Y1) | Legacy/maintenance | Auto, scale to zero | ❌ | ❌ |
| Premium (EP1-EP3) | No cold starts, longer execution, slots | Auto, min instances | ✅ | ✅ 20 slots |
| Dedicated | Predictable load, existing App Service | Manual or auto | ✅ | ✅ varies by SKU |

> ⚠️ **Deployment Slots Guidance:**
> - **Windows Consumption (Y1)** supports 1 staging slot — valid for existing apps or specific Windows requirements.
> Prefer **Elastic Premium (EP1)** or **Dedicated** for new apps requiring slots, as Consumption cold starts affect swap reliability.
> - **Linux Consumption and Flex Consumption** do **not** support deployment slots.
> - For new projects needing slots: use **Elastic Premium** or an **App Service Plan (Standard+)**.

## Runtime Stacks

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,14 @@ resource storageRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-

**⚠️ Not recommended for new deployments. Use Flex Consumption instead.**

> 💡 **OS and Slots Matter for Consumption:**
> - **Linux Consumption** (`kind: 'functionapp,linux'`, `reserved: true`): Does **not** support deployment slots.
> - **Windows Consumption** (`kind: 'functionapp'`, no `reserved`): Supports **1 staging slot** (2 total including production).
> If a user specifically needs Windows Consumption with a slot, that is supported — use the Windows pattern below.
> For new apps needing slots, prefer **Elastic Premium (EP1)** for better performance and no cold-start issues.

### Linux Consumption (no slot support)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linux Consumption also supports 1 slot but should not be recommended in light of deprecation


```bicep
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: '${resourcePrefix}func${uniqueHash}'
Expand All @@ -161,16 +169,86 @@ resource functionApp 'Microsoft.Web/sites@2022-09-01' = {
serverFarmId: functionAppPlan.id
httpsOnly: true
siteConfig: {
linuxFxVersion: 'Node|18'
linuxFxVersion: 'Node|20'
appSettings: [
{ name: 'AzureWebJobsStorage', value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value}' }
{ name: 'FUNCTIONS_EXTENSION_VERSION', value: '~4' }
{ name: 'FUNCTIONS_WORKER_RUNTIME', value: 'node' }
{ name: 'APPLICATIONINSIGHTS_CONNECTION_STRING', value: applicationInsights.properties.ConnectionString }
]
}
}
}
```

### Windows Consumption (supports 1 staging slot)

> ⚠️ **Windows Consumption is not recommended for new projects** — consider Flex Consumption or Elastic Premium.
> Use this pattern only for existing Windows apps or when Windows-specific features are required.

```bicep
resource functionAppPlan 'Microsoft.Web/serverfarms@2022-09-01' = {
name: '${resourcePrefix}-funcplan-${uniqueHash}'
location: location
sku: { name: 'Y1', tier: 'Dynamic' }
// No 'reserved: true' for Windows
}

resource functionApp 'Microsoft.Web/sites@2022-09-01' = {
name: '${resourcePrefix}-${serviceName}-${uniqueHash}'
location: location
kind: 'functionapp' // Windows (no 'linux' suffix)
identity: { type: 'SystemAssigned' }
properties: {
serverFarmId: functionAppPlan.id
httpsOnly: true
siteConfig: {
appSettings: [
{ name: 'WEBSITE_NODE_DEFAULT_VERSION', value: '~20' }
{ name: 'FUNCTIONS_EXTENSION_VERSION', value: '~4' }
{ name: 'FUNCTIONS_WORKER_RUNTIME', value: 'node' }
{ name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING', value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value}' }
{ name: 'WEBSITE_CONTENTSHARE', value: '${toLower(serviceName)}-prod' }
{ name: 'AzureWebJobsStorage', value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value}' }
{ name: 'APPLICATIONINSIGHTS_CONNECTION_STRING', value: applicationInsights.properties.ConnectionString }
]
}
}
}

// 1 staging slot is supported on Windows Consumption
resource stagingSlot 'Microsoft.Web/sites/slots@2022-09-01' = {
parent: functionApp
name: 'staging'
location: location
kind: 'functionapp'
properties: {
serverFarmId: functionAppPlan.id
siteConfig: {
appSettings: [
{ name: 'WEBSITE_NODE_DEFAULT_VERSION', value: '~20' }
{ name: 'FUNCTIONS_EXTENSION_VERSION', value: '~4' }
{ name: 'FUNCTIONS_WORKER_RUNTIME', value: 'node' }
{ name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING', value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value}' }
{ name: 'WEBSITE_CONTENTSHARE', value: '${toLower(serviceName)}-staging' } // MUST differ from production
{ name: 'AzureWebJobsStorage', value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value}' }
{ name: 'APPLICATIONINSIGHTS_CONNECTION_STRING', value: applicationInsights.properties.ConnectionString }
]
}
}
}

// Sticky settings — do not swap WEBSITE_CONTENTSHARE between slots
resource slotConfigNames 'Microsoft.Web/sites/config@2022-09-01' = {
parent: functionApp
name: 'slotConfigNames'
properties: {
appSettingNames: [
'WEBSITE_CONTENTSHARE'
'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
]
}
}
```

## Service Bus Integration (Managed Identity)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,14 @@ module "function_app" {

**⚠️ Not recommended for new deployments. Use Flex Consumption instead.**

> 💡 **OS and Slots Matter for Consumption:**
> - **Linux Consumption** (`os_type = "Linux"`): Does **not** support deployment slots.
> - **Windows Consumption** (`os_type = "Windows"`): Supports **1 staging slot** (2 total including production).
> If a user specifically needs Windows Consumption with a slot, that is supported — use the Windows pattern below.
> For new apps needing slots, prefer **Elastic Premium (EP1)** for better performance and no cold-start issues.

### Linux Consumption (no slot support)

```hcl
resource "azurerm_storage_account" "function_storage" {
name = "${var.resource_prefix}func${var.unique_hash}"
Expand Down Expand Up @@ -226,6 +234,77 @@ resource "azurerm_linux_function_app" "function_app" {
}
```

### Windows Consumption (supports 1 staging slot)

> ⚠️ **Windows Consumption is not recommended for new projects** — consider Flex Consumption or Elastic Premium.
> Use this pattern only for existing Windows apps or when Windows-specific features are required.

```hcl
resource "azurerm_service_plan" "function_plan" {
name = "${var.resource_prefix}-funcplan-${var.unique_hash}"
location = var.location
resource_group_name = azurerm_resource_group.main.name
os_type = "Windows"
sku_name = "Y1"
}

resource "azurerm_windows_function_app" "function_app" {
name = "${var.resource_prefix}-${var.service_name}-${var.unique_hash}"
location = var.location
resource_group_name = azurerm_resource_group.main.name
service_plan_id = azurerm_service_plan.function_plan.id
https_only = true

storage_account_name = azurerm_storage_account.function_storage.name
storage_account_access_key = azurerm_storage_account.function_storage.primary_access_key

site_config {
application_insights_connection_string = azurerm_application_insights.function_insights.connection_string
application_stack {
node_version = "~20"
}
}

app_settings = {
"FUNCTIONS_EXTENSION_VERSION" = "~4"
"FUNCTIONS_WORKER_RUNTIME" = "node"
"WEBSITE_CONTENTSHARE" = "${var.service_name}-prod" # must differ per slot
"WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" = azurerm_storage_account.function_storage.primary_connection_string
}

sticky_settings {
app_setting_names = ["WEBSITE_CONTENTSHARE", "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"]
}

identity {
type = "SystemAssigned"
}
}

# 1 staging slot is supported on Windows Consumption
resource "azurerm_windows_function_app_slot" "staging" {
name = "staging"
function_app_id = azurerm_windows_function_app.function_app.id

storage_account_name = azurerm_storage_account.function_storage.name
storage_account_access_key = azurerm_storage_account.function_storage.primary_access_key

site_config {
application_insights_connection_string = azurerm_application_insights.function_insights.connection_string
application_stack {
node_version = "~20"
}
}

app_settings = {
"FUNCTIONS_EXTENSION_VERSION" = "~4"
"FUNCTIONS_WORKER_RUNTIME" = "node"
"WEBSITE_CONTENTSHARE" = "${var.service_name}-staging" # MUST differ from production
"WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" = azurerm_storage_account.function_storage.primary_connection_string
}
}
```

## Service Bus Integration (Managed Identity)

```hcl
Expand Down