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 association, Flex Consumption function app configuration, and app cloning across regions.

Web apps depend on App Service plans or Flex Consumption hosting for compute resources. Function apps reference storage accounts and Application Insights for deployment and monitoring. The examples are intentionally small. Combine them with your own hosting infrastructure, networking, and identity 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 the app to an App Service plan that controls scaling, pricing, and available features. The kind property identifies this as a standard web app rather than a function app or container. Without additional configuration, the app uses default settings for runtime, networking, and authentication.

Deploy a Flex Consumption function app with runtime configuration

Azure Functions on Flex Consumption provide event-driven compute with automatic scaling and pay-per-execution billing.

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 the function app’s behavior. The runtime property sets the language and version (Python 3.11 here). The deployment.storage property points to a blob container for function code, authenticated via a connection string stored in app settings. The scaleAndConcurrency block sets memory per instance (2048 MB) and maximum instance count (100), controlling how the platform scales under load.

Configure always-ready instances and concurrency limits

Production function apps often maintain warm instances to avoid cold starts and set per-instance concurrency limits to control resource usage.

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 a minimum number of instances warm for specific trigger types (2 HTTP instances here). The triggers.http.perInstanceConcurrency property limits how many concurrent requests each instance handles (16 here), preventing resource exhaustion under sudden load spikes. This configuration extends the basic Flex Consumption setup with performance tuning for production workloads.

Clone an existing web app to a new region

Teams deploying across regions often clone existing apps rather than rebuilding configuration.

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 copies an app from sourceWebAppId to a new location. The appSettingsOverrides property selectively replaces settings in the cloned app without modifying the source. Setting cloneCustomHostNames and cloneSourceControl to true copies custom domains and Git configuration. The overwrite property controls whether to replace an existing app at the destination.

Beyond these examples

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

The examples reference pre-existing infrastructure such as App Service plans or Flex Consumption hosting, storage accounts for function deployment and state, Application Insights for monitoring, and source web apps for cloning scenarios. They focus on configuring the web app resource rather than provisioning the surrounding infrastructure.

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

  • Site configuration (siteConfig block with connection strings, handlers, runtime versions)
  • Managed identity and Key Vault integration
  • Virtual network integration (virtualNetworkSubnetId)
  • Custom domains and SSL certificates (hostNameSslStates)
  • HTTPS enforcement and client certificate authentication
  • Deployment slots and swap operations

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 be changed after creating a web app?
Several properties are immutable and require resource recreation if changed: location, name, kind, cloningInfo, hostingEnvironmentProfile, hyperV, isXenon, and reserved.
Why isn't siteConfig showing up in my Pulumi outputs?
The siteConfig property may contain sensitive information and isn’t returned in normal create and read responses. You’ll need to query it explicitly if needed.
Should I use hyperV or isXenon for Hyper-V sandbox configuration?
Use hyperV. The isXenon property is obsolete and maintained only for backward compatibility.
What does the kind property control?
The kind property determines the app type (web app, function app, mobile backend, or API app). It’s immutable after creation. For app resources, refer to Azure documentation for supported values and format requirements.
How do I clone an existing web app?
Configure cloningInfo with sourceWebAppId and sourceWebAppLocation. You can optionally override app settings, clone custom hostnames, and clone source control using appSettingsOverrides, cloneCustomHostNames, and cloneSourceControl.
Security & Networking
How do I enable client certificate authentication for my app?
Set clientCertEnabled to true to enable TLS mutual authentication. Then configure clientCertMode as Required (certificate mandatory) or Optional (certificate accepted but not required). When clientCertEnabled is false, clientCertMode is ignored.
What happens when I set hostNamesDisabled to true?
The app becomes only accessible via API Management process. Public hostnames are disabled, preventing direct access to the app.
How do I enforce HTTPS-only access?
Set httpsOnly to true. This configures the app to accept only HTTPS requests and issues redirects for HTTP requests.
How do I connect my app to a virtual network?
Use virtualNetworkSubnetId with the Azure Resource Manager ID in the format /subscriptions/{subscriptionName}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{vnetName}/subnets/{subnetName} for Regional VNET Integration.
Function Apps & Flex Consumption
How do I create a Flex Consumption function app?
Set kind to functionapp,linux and configure functionAppConfig with three main sections: deployment.storage (authentication and blob container URL), runtime (name like python and version like 3.11), and scaleAndConcurrency (instanceMemoryMB and maximumInstanceCount). Include AzureWebJobsStorage and APPLICATIONINSIGHTS_CONNECTION_STRING in siteConfig.appSettings.
How do I configure always-ready instances and per-instance concurrency?
Use functionAppConfig.scaleAndConcurrency.alwaysReady to specify pre-warmed instances with instanceCount and trigger name. For HTTP triggers, set triggers.http.perInstanceConcurrency to control concurrent requests per instance.

Using a different cloud?

Explore compute guides for other cloud providers: