Deploy Azure App Service Web Apps

The azure-native:web:WebApp resource, part of the Pulumi Azure Native provider, defines an Azure web app, function app, or mobile backend: its hosting plan, runtime configuration, and deployment settings. This guide focuses on three capabilities: App Service plan integration, Flex Consumption function apps, and app cloning across regions.

Web apps depend on App Service plans for compute resources. Function apps require storage accounts and Application Insights for runtime and monitoring. The examples are intentionally small. Combine them with your own infrastructure and configuration.

Create a web app with an App Service plan

Most deployments link a web app to an existing App Service plan, which defines compute resources and pricing tier.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const webApp = new azure_native.web.WebApp("webApp", {
    kind: "app",
    location: "East US",
    name: "sitef6141",
    resourceGroupName: "testrg123",
    serverFarmId: "/subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg123/providers/Microsoft.Web/serverfarms/DefaultAsp",
});
import pulumi
import pulumi_azure_native as azure_native

web_app = azure_native.web.WebApp("webApp",
    kind="app",
    location="East US",
    name="sitef6141",
    resource_group_name="testrg123",
    server_farm_id="/subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg123/providers/Microsoft.Web/serverfarms/DefaultAsp")
package main

import (
	web "github.com/pulumi/pulumi-azure-native-sdk/web/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := web.NewWebApp(ctx, "webApp", &web.WebAppArgs{
			Kind:              pulumi.String("app"),
			Location:          pulumi.String("East US"),
			Name:              pulumi.String("sitef6141"),
			ResourceGroupName: pulumi.String("testrg123"),
			ServerFarmId:      pulumi.String("/subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg123/providers/Microsoft.Web/serverfarms/DefaultAsp"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var webApp = new AzureNative.Web.WebApp("webApp", new()
    {
        Kind = "app",
        Location = "East US",
        Name = "sitef6141",
        ResourceGroupName = "testrg123",
        ServerFarmId = "/subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg123/providers/Microsoft.Web/serverfarms/DefaultAsp",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.web.WebApp;
import com.pulumi.azurenative.web.WebAppArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var webApp = new WebApp("webApp", WebAppArgs.builder()
            .kind("app")
            .location("East US")
            .name("sitef6141")
            .resourceGroupName("testrg123")
            .serverFarmId("/subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg123/providers/Microsoft.Web/serverfarms/DefaultAsp")
            .build());

    }
}
resources:
  webApp:
    type: azure-native:web:WebApp
    properties:
      kind: app
      location: East US
      name: sitef6141
      resourceGroupName: testrg123
      serverFarmId: /subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg123/providers/Microsoft.Web/serverfarms/DefaultAsp

The serverFarmId property connects your app to an App Service plan that controls scaling and pricing. The kind property distinguishes web apps (“app”) from function apps (“functionapp”). The location determines the Azure region where the app runs.

Deploy a Flex Consumption function app

Azure Functions on Flex Consumption provides serverless compute with per-second billing and automatic scaling.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const webApp = new azure_native.web.WebApp("webApp", {
    functionAppConfig: {
        deployment: {
            storage: {
                authentication: {
                    storageAccountConnectionStringName: "TheAppSettingName",
                    type: azure_native.web.AuthenticationType.StorageAccountConnectionString,
                },
                type: azure_native.web.FunctionsDeploymentStorageType.BlobContainer,
                value: "https://storageAccountName.blob.core.windows.net/containername",
            },
        },
        runtime: {
            name: azure_native.web.RuntimeName.Python,
            version: "3.11",
        },
        scaleAndConcurrency: {
            instanceMemoryMB: 2048,
            maximumInstanceCount: 100,
        },
    },
    kind: "functionapp,linux",
    location: "East US",
    name: "sitef6141",
    resourceGroupName: "testrg123",
    siteConfig: {
        appSettings: [
            {
                name: "AzureWebJobsStorage",
                value: "DefaultEndpointsProtocol=https;AccountName=StorageAccountName;AccountKey=Sanitized;EndpointSuffix=core.windows.net",
            },
            {
                name: "APPLICATIONINSIGHTS_CONNECTION_STRING",
                value: "InstrumentationKey=Sanitized;IngestionEndpoint=Sanitized;LiveEndpoint=Sanitized",
            },
        ],
    },
});
import pulumi
import pulumi_azure_native as azure_native

web_app = azure_native.web.WebApp("webApp",
    function_app_config={
        "deployment": {
            "storage": {
                "authentication": {
                    "storage_account_connection_string_name": "TheAppSettingName",
                    "type": azure_native.web.AuthenticationType.STORAGE_ACCOUNT_CONNECTION_STRING,
                },
                "type": azure_native.web.FunctionsDeploymentStorageType.BLOB_CONTAINER,
                "value": "https://storageAccountName.blob.core.windows.net/containername",
            },
        },
        "runtime": {
            "name": azure_native.web.RuntimeName.PYTHON,
            "version": "3.11",
        },
        "scale_and_concurrency": {
            "instance_memory_mb": 2048,
            "maximum_instance_count": 100,
        },
    },
    kind="functionapp,linux",
    location="East US",
    name="sitef6141",
    resource_group_name="testrg123",
    site_config={
        "app_settings": [
            {
                "name": "AzureWebJobsStorage",
                "value": "DefaultEndpointsProtocol=https;AccountName=StorageAccountName;AccountKey=Sanitized;EndpointSuffix=core.windows.net",
            },
            {
                "name": "APPLICATIONINSIGHTS_CONNECTION_STRING",
                "value": "InstrumentationKey=Sanitized;IngestionEndpoint=Sanitized;LiveEndpoint=Sanitized",
            },
        ],
    })
package main

import (
	web "github.com/pulumi/pulumi-azure-native-sdk/web/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := web.NewWebApp(ctx, "webApp", &web.WebAppArgs{
			FunctionAppConfig: &web.FunctionAppConfigArgs{
				Deployment: &web.FunctionsDeploymentArgs{
					Storage: &web.FunctionsDeploymentStorageArgs{
						Authentication: &web.FunctionsDeploymentAuthenticationArgs{
							StorageAccountConnectionStringName: pulumi.String("TheAppSettingName"),
							Type:                               pulumi.String(web.AuthenticationTypeStorageAccountConnectionString),
						},
						Type:  pulumi.String(web.FunctionsDeploymentStorageTypeBlobContainer),
						Value: pulumi.String("https://storageAccountName.blob.core.windows.net/containername"),
					},
				},
				Runtime: &web.FunctionsRuntimeArgs{
					Name:    pulumi.String(web.RuntimeNamePython),
					Version: pulumi.String("3.11"),
				},
				ScaleAndConcurrency: &web.FunctionsScaleAndConcurrencyArgs{
					InstanceMemoryMB:     pulumi.Int(2048),
					MaximumInstanceCount: pulumi.Int(100),
				},
			},
			Kind:              pulumi.String("functionapp,linux"),
			Location:          pulumi.String("East US"),
			Name:              pulumi.String("sitef6141"),
			ResourceGroupName: pulumi.String("testrg123"),
			SiteConfig: &web.SiteConfigArgs{
				AppSettings: web.NameValuePairArray{
					&web.NameValuePairArgs{
						Name:  pulumi.String("AzureWebJobsStorage"),
						Value: pulumi.String("DefaultEndpointsProtocol=https;AccountName=StorageAccountName;AccountKey=Sanitized;EndpointSuffix=core.windows.net"),
					},
					&web.NameValuePairArgs{
						Name:  pulumi.String("APPLICATIONINSIGHTS_CONNECTION_STRING"),
						Value: pulumi.String("InstrumentationKey=Sanitized;IngestionEndpoint=Sanitized;LiveEndpoint=Sanitized"),
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var webApp = new AzureNative.Web.WebApp("webApp", new()
    {
        FunctionAppConfig = new AzureNative.Web.Inputs.FunctionAppConfigArgs
        {
            Deployment = new AzureNative.Web.Inputs.FunctionsDeploymentArgs
            {
                Storage = new AzureNative.Web.Inputs.FunctionsDeploymentStorageArgs
                {
                    Authentication = new AzureNative.Web.Inputs.FunctionsDeploymentAuthenticationArgs
                    {
                        StorageAccountConnectionStringName = "TheAppSettingName",
                        Type = AzureNative.Web.AuthenticationType.StorageAccountConnectionString,
                    },
                    Type = AzureNative.Web.FunctionsDeploymentStorageType.BlobContainer,
                    Value = "https://storageAccountName.blob.core.windows.net/containername",
                },
            },
            Runtime = new AzureNative.Web.Inputs.FunctionsRuntimeArgs
            {
                Name = AzureNative.Web.RuntimeName.Python,
                Version = "3.11",
            },
            ScaleAndConcurrency = new AzureNative.Web.Inputs.FunctionsScaleAndConcurrencyArgs
            {
                InstanceMemoryMB = 2048,
                MaximumInstanceCount = 100,
            },
        },
        Kind = "functionapp,linux",
        Location = "East US",
        Name = "sitef6141",
        ResourceGroupName = "testrg123",
        SiteConfig = new AzureNative.Web.Inputs.SiteConfigArgs
        {
            AppSettings = new[]
            {
                new AzureNative.Web.Inputs.NameValuePairArgs
                {
                    Name = "AzureWebJobsStorage",
                    Value = "DefaultEndpointsProtocol=https;AccountName=StorageAccountName;AccountKey=Sanitized;EndpointSuffix=core.windows.net",
                },
                new AzureNative.Web.Inputs.NameValuePairArgs
                {
                    Name = "APPLICATIONINSIGHTS_CONNECTION_STRING",
                    Value = "InstrumentationKey=Sanitized;IngestionEndpoint=Sanitized;LiveEndpoint=Sanitized",
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.web.WebApp;
import com.pulumi.azurenative.web.WebAppArgs;
import com.pulumi.azurenative.web.inputs.FunctionAppConfigArgs;
import com.pulumi.azurenative.web.inputs.FunctionsDeploymentArgs;
import com.pulumi.azurenative.web.inputs.FunctionsDeploymentStorageArgs;
import com.pulumi.azurenative.web.inputs.FunctionsDeploymentAuthenticationArgs;
import com.pulumi.azurenative.web.inputs.FunctionsRuntimeArgs;
import com.pulumi.azurenative.web.inputs.FunctionsScaleAndConcurrencyArgs;
import com.pulumi.azurenative.web.inputs.SiteConfigArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var webApp = new WebApp("webApp", WebAppArgs.builder()
            .functionAppConfig(FunctionAppConfigArgs.builder()
                .deployment(FunctionsDeploymentArgs.builder()
                    .storage(FunctionsDeploymentStorageArgs.builder()
                        .authentication(FunctionsDeploymentAuthenticationArgs.builder()
                            .storageAccountConnectionStringName("TheAppSettingName")
                            .type("StorageAccountConnectionString")
                            .build())
                        .type("blobContainer")
                        .value("https://storageAccountName.blob.core.windows.net/containername")
                        .build())
                    .build())
                .runtime(FunctionsRuntimeArgs.builder()
                    .name("python")
                    .version("3.11")
                    .build())
                .scaleAndConcurrency(FunctionsScaleAndConcurrencyArgs.builder()
                    .instanceMemoryMB(2048)
                    .maximumInstanceCount(100)
                    .build())
                .build())
            .kind("functionapp,linux")
            .location("East US")
            .name("sitef6141")
            .resourceGroupName("testrg123")
            .siteConfig(SiteConfigArgs.builder()
                .appSettings(                
                    NameValuePairArgs.builder()
                        .name("AzureWebJobsStorage")
                        .value("DefaultEndpointsProtocol=https;AccountName=StorageAccountName;AccountKey=Sanitized;EndpointSuffix=core.windows.net")
                        .build(),
                    NameValuePairArgs.builder()
                        .name("APPLICATIONINSIGHTS_CONNECTION_STRING")
                        .value("InstrumentationKey=Sanitized;IngestionEndpoint=Sanitized;LiveEndpoint=Sanitized")
                        .build())
                .build())
            .build());

    }
}
resources:
  webApp:
    type: azure-native:web:WebApp
    properties:
      functionAppConfig:
        deployment:
          storage:
            authentication:
              storageAccountConnectionStringName: TheAppSettingName
              type: StorageAccountConnectionString
            type: blobContainer
            value: https://storageAccountName.blob.core.windows.net/containername
        runtime:
          name: python
          version: '3.11'
        scaleAndConcurrency:
          instanceMemoryMB: 2048
          maximumInstanceCount: 100
      kind: functionapp,linux
      location: East US
      name: sitef6141
      resourceGroupName: testrg123
      siteConfig:
        appSettings:
          - name: AzureWebJobsStorage
            value: DefaultEndpointsProtocol=https;AccountName=StorageAccountName;AccountKey=Sanitized;EndpointSuffix=core.windows.net
          - name: APPLICATIONINSIGHTS_CONNECTION_STRING
            value: InstrumentationKey=Sanitized;IngestionEndpoint=Sanitized;LiveEndpoint=Sanitized

The functionAppConfig block defines runtime (Python 3.11), deployment storage (blob container with connection string authentication), and scaling limits (up to 100 instances, 2048 MB per instance). The siteConfig.appSettings array passes connection strings for storage and Application Insights. Flex Consumption apps scale automatically based on demand without pre-allocated capacity.

Configure always-ready instances and concurrency

Production function apps often maintain warm instances to avoid cold starts and tune concurrency per trigger type.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const webApp = new azure_native.web.WebApp("webApp", {
    functionAppConfig: {
        deployment: {
            storage: {
                authentication: {
                    storageAccountConnectionStringName: "TheAppSettingName",
                    type: azure_native.web.AuthenticationType.StorageAccountConnectionString,
                },
                type: azure_native.web.FunctionsDeploymentStorageType.BlobContainer,
                value: "https://storageAccountName.blob.core.windows.net/containername",
            },
        },
        runtime: {
            name: azure_native.web.RuntimeName.Python,
            version: "3.11",
        },
        scaleAndConcurrency: {
            alwaysReady: [{
                instanceCount: 2,
                name: "http",
            }],
            instanceMemoryMB: 2048,
            maximumInstanceCount: 100,
            triggers: {
                http: {
                    perInstanceConcurrency: 16,
                },
            },
        },
    },
    kind: "functionapp,linux",
    location: "East US",
    name: "sitef6141",
    resourceGroupName: "testrg123",
    siteConfig: {
        appSettings: [
            {
                name: "AzureWebJobsStorage",
                value: "DefaultEndpointsProtocol=https;AccountName=StorageAccountName;AccountKey=Sanitized;EndpointSuffix=core.windows.net",
            },
            {
                name: "APPLICATIONINSIGHTS_CONNECTION_STRING",
                value: "InstrumentationKey=Sanitized;IngestionEndpoint=Sanitized;LiveEndpoint=Sanitized",
            },
        ],
    },
});
import pulumi
import pulumi_azure_native as azure_native

web_app = azure_native.web.WebApp("webApp",
    function_app_config={
        "deployment": {
            "storage": {
                "authentication": {
                    "storage_account_connection_string_name": "TheAppSettingName",
                    "type": azure_native.web.AuthenticationType.STORAGE_ACCOUNT_CONNECTION_STRING,
                },
                "type": azure_native.web.FunctionsDeploymentStorageType.BLOB_CONTAINER,
                "value": "https://storageAccountName.blob.core.windows.net/containername",
            },
        },
        "runtime": {
            "name": azure_native.web.RuntimeName.PYTHON,
            "version": "3.11",
        },
        "scale_and_concurrency": {
            "always_ready": [{
                "instance_count": 2,
                "name": "http",
            }],
            "instance_memory_mb": 2048,
            "maximum_instance_count": 100,
            "triggers": {
                "http": {
                    "per_instance_concurrency": 16,
                },
            },
        },
    },
    kind="functionapp,linux",
    location="East US",
    name="sitef6141",
    resource_group_name="testrg123",
    site_config={
        "app_settings": [
            {
                "name": "AzureWebJobsStorage",
                "value": "DefaultEndpointsProtocol=https;AccountName=StorageAccountName;AccountKey=Sanitized;EndpointSuffix=core.windows.net",
            },
            {
                "name": "APPLICATIONINSIGHTS_CONNECTION_STRING",
                "value": "InstrumentationKey=Sanitized;IngestionEndpoint=Sanitized;LiveEndpoint=Sanitized",
            },
        ],
    })
package main

import (
	web "github.com/pulumi/pulumi-azure-native-sdk/web/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := web.NewWebApp(ctx, "webApp", &web.WebAppArgs{
			FunctionAppConfig: &web.FunctionAppConfigArgs{
				Deployment: &web.FunctionsDeploymentArgs{
					Storage: &web.FunctionsDeploymentStorageArgs{
						Authentication: &web.FunctionsDeploymentAuthenticationArgs{
							StorageAccountConnectionStringName: pulumi.String("TheAppSettingName"),
							Type:                               pulumi.String(web.AuthenticationTypeStorageAccountConnectionString),
						},
						Type:  pulumi.String(web.FunctionsDeploymentStorageTypeBlobContainer),
						Value: pulumi.String("https://storageAccountName.blob.core.windows.net/containername"),
					},
				},
				Runtime: &web.FunctionsRuntimeArgs{
					Name:    pulumi.String(web.RuntimeNamePython),
					Version: pulumi.String("3.11"),
				},
				ScaleAndConcurrency: &web.FunctionsScaleAndConcurrencyArgs{
					AlwaysReady: web.FunctionsAlwaysReadyConfigArray{
						&web.FunctionsAlwaysReadyConfigArgs{
							InstanceCount: pulumi.Int(2),
							Name:          pulumi.String("http"),
						},
					},
					InstanceMemoryMB:     pulumi.Int(2048),
					MaximumInstanceCount: pulumi.Int(100),
					Triggers: &web.FunctionsScaleAndConcurrencyTriggersArgs{
						Http: &web.FunctionsScaleAndConcurrencyHttpArgs{
							PerInstanceConcurrency: pulumi.Int(16),
						},
					},
				},
			},
			Kind:              pulumi.String("functionapp,linux"),
			Location:          pulumi.String("East US"),
			Name:              pulumi.String("sitef6141"),
			ResourceGroupName: pulumi.String("testrg123"),
			SiteConfig: &web.SiteConfigArgs{
				AppSettings: web.NameValuePairArray{
					&web.NameValuePairArgs{
						Name:  pulumi.String("AzureWebJobsStorage"),
						Value: pulumi.String("DefaultEndpointsProtocol=https;AccountName=StorageAccountName;AccountKey=Sanitized;EndpointSuffix=core.windows.net"),
					},
					&web.NameValuePairArgs{
						Name:  pulumi.String("APPLICATIONINSIGHTS_CONNECTION_STRING"),
						Value: pulumi.String("InstrumentationKey=Sanitized;IngestionEndpoint=Sanitized;LiveEndpoint=Sanitized"),
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var webApp = new AzureNative.Web.WebApp("webApp", new()
    {
        FunctionAppConfig = new AzureNative.Web.Inputs.FunctionAppConfigArgs
        {
            Deployment = new AzureNative.Web.Inputs.FunctionsDeploymentArgs
            {
                Storage = new AzureNative.Web.Inputs.FunctionsDeploymentStorageArgs
                {
                    Authentication = new AzureNative.Web.Inputs.FunctionsDeploymentAuthenticationArgs
                    {
                        StorageAccountConnectionStringName = "TheAppSettingName",
                        Type = AzureNative.Web.AuthenticationType.StorageAccountConnectionString,
                    },
                    Type = AzureNative.Web.FunctionsDeploymentStorageType.BlobContainer,
                    Value = "https://storageAccountName.blob.core.windows.net/containername",
                },
            },
            Runtime = new AzureNative.Web.Inputs.FunctionsRuntimeArgs
            {
                Name = AzureNative.Web.RuntimeName.Python,
                Version = "3.11",
            },
            ScaleAndConcurrency = new AzureNative.Web.Inputs.FunctionsScaleAndConcurrencyArgs
            {
                AlwaysReady = new[]
                {
                    new AzureNative.Web.Inputs.FunctionsAlwaysReadyConfigArgs
                    {
                        InstanceCount = 2,
                        Name = "http",
                    },
                },
                InstanceMemoryMB = 2048,
                MaximumInstanceCount = 100,
                Triggers = new AzureNative.Web.Inputs.FunctionsScaleAndConcurrencyTriggersArgs
                {
                    Http = new AzureNative.Web.Inputs.FunctionsScaleAndConcurrencyHttpArgs
                    {
                        PerInstanceConcurrency = 16,
                    },
                },
            },
        },
        Kind = "functionapp,linux",
        Location = "East US",
        Name = "sitef6141",
        ResourceGroupName = "testrg123",
        SiteConfig = new AzureNative.Web.Inputs.SiteConfigArgs
        {
            AppSettings = new[]
            {
                new AzureNative.Web.Inputs.NameValuePairArgs
                {
                    Name = "AzureWebJobsStorage",
                    Value = "DefaultEndpointsProtocol=https;AccountName=StorageAccountName;AccountKey=Sanitized;EndpointSuffix=core.windows.net",
                },
                new AzureNative.Web.Inputs.NameValuePairArgs
                {
                    Name = "APPLICATIONINSIGHTS_CONNECTION_STRING",
                    Value = "InstrumentationKey=Sanitized;IngestionEndpoint=Sanitized;LiveEndpoint=Sanitized",
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.web.WebApp;
import com.pulumi.azurenative.web.WebAppArgs;
import com.pulumi.azurenative.web.inputs.FunctionAppConfigArgs;
import com.pulumi.azurenative.web.inputs.FunctionsDeploymentArgs;
import com.pulumi.azurenative.web.inputs.FunctionsDeploymentStorageArgs;
import com.pulumi.azurenative.web.inputs.FunctionsDeploymentAuthenticationArgs;
import com.pulumi.azurenative.web.inputs.FunctionsRuntimeArgs;
import com.pulumi.azurenative.web.inputs.FunctionsScaleAndConcurrencyArgs;
import com.pulumi.azurenative.web.inputs.FunctionsScaleAndConcurrencyTriggersArgs;
import com.pulumi.azurenative.web.inputs.FunctionsScaleAndConcurrencyHttpArgs;
import com.pulumi.azurenative.web.inputs.SiteConfigArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var webApp = new WebApp("webApp", WebAppArgs.builder()
            .functionAppConfig(FunctionAppConfigArgs.builder()
                .deployment(FunctionsDeploymentArgs.builder()
                    .storage(FunctionsDeploymentStorageArgs.builder()
                        .authentication(FunctionsDeploymentAuthenticationArgs.builder()
                            .storageAccountConnectionStringName("TheAppSettingName")
                            .type("StorageAccountConnectionString")
                            .build())
                        .type("blobContainer")
                        .value("https://storageAccountName.blob.core.windows.net/containername")
                        .build())
                    .build())
                .runtime(FunctionsRuntimeArgs.builder()
                    .name("python")
                    .version("3.11")
                    .build())
                .scaleAndConcurrency(FunctionsScaleAndConcurrencyArgs.builder()
                    .alwaysReady(FunctionsAlwaysReadyConfigArgs.builder()
                        .instanceCount(2)
                        .name("http")
                        .build())
                    .instanceMemoryMB(2048)
                    .maximumInstanceCount(100)
                    .triggers(FunctionsScaleAndConcurrencyTriggersArgs.builder()
                        .http(FunctionsScaleAndConcurrencyHttpArgs.builder()
                            .perInstanceConcurrency(16)
                            .build())
                        .build())
                    .build())
                .build())
            .kind("functionapp,linux")
            .location("East US")
            .name("sitef6141")
            .resourceGroupName("testrg123")
            .siteConfig(SiteConfigArgs.builder()
                .appSettings(                
                    NameValuePairArgs.builder()
                        .name("AzureWebJobsStorage")
                        .value("DefaultEndpointsProtocol=https;AccountName=StorageAccountName;AccountKey=Sanitized;EndpointSuffix=core.windows.net")
                        .build(),
                    NameValuePairArgs.builder()
                        .name("APPLICATIONINSIGHTS_CONNECTION_STRING")
                        .value("InstrumentationKey=Sanitized;IngestionEndpoint=Sanitized;LiveEndpoint=Sanitized")
                        .build())
                .build())
            .build());

    }
}
resources:
  webApp:
    type: azure-native:web:WebApp
    properties:
      functionAppConfig:
        deployment:
          storage:
            authentication:
              storageAccountConnectionStringName: TheAppSettingName
              type: StorageAccountConnectionString
            type: blobContainer
            value: https://storageAccountName.blob.core.windows.net/containername
        runtime:
          name: python
          version: '3.11'
        scaleAndConcurrency:
          alwaysReady:
            - instanceCount: 2
              name: http
          instanceMemoryMB: 2048
          maximumInstanceCount: 100
          triggers:
            http:
              perInstanceConcurrency: 16
      kind: functionapp,linux
      location: East US
      name: sitef6141
      resourceGroupName: testrg123
      siteConfig:
        appSettings:
          - name: AzureWebJobsStorage
            value: DefaultEndpointsProtocol=https;AccountName=StorageAccountName;AccountKey=Sanitized;EndpointSuffix=core.windows.net
          - name: APPLICATIONINSIGHTS_CONNECTION_STRING
            value: InstrumentationKey=Sanitized;IngestionEndpoint=Sanitized;LiveEndpoint=Sanitized

The alwaysReady array keeps 2 HTTP trigger instances warm at all times. The triggers.http.perInstanceConcurrency property limits each instance to 16 concurrent requests, preventing overload. This configuration extends the basic Flex Consumption setup with performance tuning for predictable latency.

Clone an existing web app to a new region

Teams expanding to new regions clone existing apps to replicate configuration while overriding specific settings.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const webApp = new azure_native.web.WebApp("webApp", {
    cloningInfo: {
        appSettingsOverrides: {
            Setting1: "NewValue1",
            Setting3: "NewValue5",
        },
        cloneCustomHostNames: true,
        cloneSourceControl: true,
        configureLoadBalancing: false,
        hostingEnvironment: "/subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg456/providers/Microsoft.Web/hostingenvironments/aseforsites",
        overwrite: false,
        sourceWebAppId: "/subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg456/providers/Microsoft.Web/sites/srcsiteg478",
        sourceWebAppLocation: "West Europe",
    },
    kind: "app",
    location: "East US",
    name: "sitef6141",
    resourceGroupName: "testrg123",
});
import pulumi
import pulumi_azure_native as azure_native

web_app = azure_native.web.WebApp("webApp",
    cloning_info={
        "app_settings_overrides": {
            "Setting1": "NewValue1",
            "Setting3": "NewValue5",
        },
        "clone_custom_host_names": True,
        "clone_source_control": True,
        "configure_load_balancing": False,
        "hosting_environment": "/subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg456/providers/Microsoft.Web/hostingenvironments/aseforsites",
        "overwrite": False,
        "source_web_app_id": "/subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg456/providers/Microsoft.Web/sites/srcsiteg478",
        "source_web_app_location": "West Europe",
    },
    kind="app",
    location="East US",
    name="sitef6141",
    resource_group_name="testrg123")
package main

import (
	web "github.com/pulumi/pulumi-azure-native-sdk/web/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := web.NewWebApp(ctx, "webApp", &web.WebAppArgs{
			CloningInfo: &web.CloningInfoArgs{
				AppSettingsOverrides: pulumi.StringMap{
					"Setting1": pulumi.String("NewValue1"),
					"Setting3": pulumi.String("NewValue5"),
				},
				CloneCustomHostNames:   pulumi.Bool(true),
				CloneSourceControl:     pulumi.Bool(true),
				ConfigureLoadBalancing: pulumi.Bool(false),
				HostingEnvironment:     pulumi.String("/subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg456/providers/Microsoft.Web/hostingenvironments/aseforsites"),
				Overwrite:              pulumi.Bool(false),
				SourceWebAppId:         pulumi.String("/subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg456/providers/Microsoft.Web/sites/srcsiteg478"),
				SourceWebAppLocation:   pulumi.String("West Europe"),
			},
			Kind:              pulumi.String("app"),
			Location:          pulumi.String("East US"),
			Name:              pulumi.String("sitef6141"),
			ResourceGroupName: pulumi.String("testrg123"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var webApp = new AzureNative.Web.WebApp("webApp", new()
    {
        CloningInfo = new AzureNative.Web.Inputs.CloningInfoArgs
        {
            AppSettingsOverrides = 
            {
                { "Setting1", "NewValue1" },
                { "Setting3", "NewValue5" },
            },
            CloneCustomHostNames = true,
            CloneSourceControl = true,
            ConfigureLoadBalancing = false,
            HostingEnvironment = "/subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg456/providers/Microsoft.Web/hostingenvironments/aseforsites",
            Overwrite = false,
            SourceWebAppId = "/subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg456/providers/Microsoft.Web/sites/srcsiteg478",
            SourceWebAppLocation = "West Europe",
        },
        Kind = "app",
        Location = "East US",
        Name = "sitef6141",
        ResourceGroupName = "testrg123",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.web.WebApp;
import com.pulumi.azurenative.web.WebAppArgs;
import com.pulumi.azurenative.web.inputs.CloningInfoArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var webApp = new WebApp("webApp", WebAppArgs.builder()
            .cloningInfo(CloningInfoArgs.builder()
                .appSettingsOverrides(Map.ofEntries(
                    Map.entry("Setting1", "NewValue1"),
                    Map.entry("Setting3", "NewValue5")
                ))
                .cloneCustomHostNames(true)
                .cloneSourceControl(true)
                .configureLoadBalancing(false)
                .hostingEnvironment("/subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg456/providers/Microsoft.Web/hostingenvironments/aseforsites")
                .overwrite(false)
                .sourceWebAppId("/subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg456/providers/Microsoft.Web/sites/srcsiteg478")
                .sourceWebAppLocation("West Europe")
                .build())
            .kind("app")
            .location("East US")
            .name("sitef6141")
            .resourceGroupName("testrg123")
            .build());

    }
}
resources:
  webApp:
    type: azure-native:web:WebApp
    properties:
      cloningInfo:
        appSettingsOverrides:
          Setting1: NewValue1
          Setting3: NewValue5
        cloneCustomHostNames: true
        cloneSourceControl: true
        configureLoadBalancing: false
        hostingEnvironment: /subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg456/providers/Microsoft.Web/hostingenvironments/aseforsites
        overwrite: false
        sourceWebAppId: /subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testrg456/providers/Microsoft.Web/sites/srcsiteg478
        sourceWebAppLocation: West Europe
      kind: app
      location: East US
      name: sitef6141
      resourceGroupName: testrg123

The cloningInfo block references a source app by ID and location, then overrides specific app settings while preserving the rest. The cloneCustomHostNames and cloneSourceControl properties control whether custom domains and source control configuration copy to the new app. This creates a new app in East US based on a West Europe source, with modified settings but identical runtime configuration.

Beyond these examples

These snippets focus on specific web app features: App Service plan integration and Flex Consumption hosting, function app runtime and scaling configuration, and app cloning with setting overrides. They’re intentionally minimal rather than full application deployments.

The examples reference pre-existing infrastructure such as App Service plans (for traditional web apps), storage accounts and Application Insights (for function apps), and source web apps (for cloning scenarios). They focus on configuring the web app rather than provisioning everything around it.

To keep things focused, common web app patterns are omitted, including:

  • Managed identity and Key Vault integration (identity, keyVaultReferenceIdentity)
  • VNet integration and private endpoints (virtualNetworkSubnetId, publicNetworkAccess)
  • Custom domains and SSL certificates (hostNameSslStates)
  • Deployment slots and traffic routing

These omissions are intentional: the goal is to illustrate how each web app feature is wired, not provide drop-in application modules. See the WebApp resource reference for all available configuration options.

Let's deploy Azure App Service Web Apps

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Resource Configuration & Immutability
What properties can't I change after creating the web app?
Several properties are immutable after creation: location, name, cloningInfo, hostingEnvironmentProfile, hyperV, isXenon, kind, reserved, and resourceGroupName.
What's the difference between hyperV and isXenon?
Both properties configure Hyper-V sandbox settings. The isXenon property is obsolete and should not be used; configure hyperV instead. Both default to false and are immutable.
What values can I use for the kind property?
The kind property specifies the resource type (e.g., app, functionapp,linux). For apps, valid values are documented at https://github.com/Azure/app-service-linux-docs/blob/master/Things_You_Should_Know/kind_property.md#app-service-resource-kind-reference.
Cloning & Migration
How do I clone an existing web app?
Configure cloningInfo with sourceWebAppId and sourceWebAppLocation. Use appSettingsOverrides to override specific settings, and set cloneCustomHostNames or cloneSourceControl to include those resources.
Can I overwrite the destination app when cloning?
Yes, set cloningInfo.overwrite to true. The example shows this set to false by default.
Function Apps
How do I configure a Flex Consumption function app?
Set functionAppConfig with three key sections: deployment (storage authentication and location), runtime (name and version like Python 3.11), and scaleAndConcurrency (instanceMemoryMB and maximumInstanceCount). Also configure siteConfig.appSettings with AzureWebJobsStorage and APPLICATIONINSIGHTS_CONNECTION_STRING.
How do I configure always-ready instances for my function app?
Use functionAppConfig.scaleAndConcurrency.alwaysReady with an array specifying name (e.g., http) and instanceCount (e.g., 2).
How do I set per-instance concurrency for HTTP triggers?
Configure functionAppConfig.scaleAndConcurrency.triggers.http.perInstanceConcurrency with the desired value (e.g., 16).
Networking & Security
What are the VNET configuration options?
You can configure five VNET-related properties: virtualNetworkSubnetId (for Regional VNET Integration), vnetRouteAllEnabled (applies security groups and routes to outbound traffic), vnetBackupRestoreEnabled, vnetContentShareEnabled, and vnetImagePullEnabled.
How do client certificate settings work together?
The clientCertMode property composes with clientCertEnabled. When clientCertEnabled is false, client certificates are ignored. When true, set clientCertMode to Required (certificate required) or Optional (certificate accepted but not required).

Using a different cloud?

Explore compute guides for other cloud providers: