Azure Functions Premium Plan - When and Why
Introduction
Azure Functions Premium plan provides enhanced performance, VNet connectivity, and predictable pricing compared to the Consumption plan. Understanding when to use Premium versus Consumption is crucial for optimizing both cost and performance of your serverless workloads.
In this post, we will explore the Premium plan features and when to choose it over Consumption.
Premium Plan Features
The Premium plan offers several advantages:
- Pre-warmed instances: Eliminate cold starts
- VNet integration: Connect to private resources
- Unlimited execution time: No 5/10 minute timeout
- More powerful instances: Up to 14GB memory
- Premium storage: Faster storage performance
Creating a Premium Function App
Deploy a Premium function app:
# Create Premium App Service Plan
az functionapp plan create \
--resource-group rg-functions \
--name premium-plan \
--location eastus \
--sku EP1 \
--min-instances 1 \
--max-burst 10
# Create Function App on Premium plan
az functionapp create \
--resource-group rg-functions \
--name myfunc-premium \
--storage-account funcstorageaccount \
--plan premium-plan \
--runtime dotnet \
--runtime-version 6 \
--functions-version 4
# Configure VNet integration
az functionapp vnet-integration add \
--resource-group rg-functions \
--name myfunc-premium \
--vnet vnet-main \
--subnet subnet-functions
Terraform Configuration
Complete Premium function app setup:
# Premium App Service Plan
resource "azurerm_service_plan" "premium" {
name = "premium-functions-plan"
resource_group_name = azurerm_resource_group.functions.name
location = azurerm_resource_group.functions.location
os_type = "Linux"
sku_name = "EP1"
tags = {
Environment = "Production"
}
}
# Function App
resource "azurerm_linux_function_app" "premium" {
name = "myfunc-premium"
resource_group_name = azurerm_resource_group.functions.name
location = azurerm_resource_group.functions.location
storage_account_name = azurerm_storage_account.functions.name
storage_account_access_key = azurerm_storage_account.functions.primary_access_key
service_plan_id = azurerm_service_plan.premium.id
site_config {
always_on = true
application_stack {
dotnet_version = "6.0"
}
# Pre-warmed instances
pre_warmed_instance_count = 1
# Elastic scale settings
elastic_instance_minimum = 1
# VNet integration
vnet_route_all_enabled = true
}
app_settings = {
"FUNCTIONS_WORKER_RUNTIME" = "dotnet"
"WEBSITE_RUN_FROM_PACKAGE" = "1"
"APPINSIGHTS_INSTRUMENTATIONKEY" = azurerm_application_insights.functions.instrumentation_key
# Connection strings for private resources
"SqlConnectionString" = "@Microsoft.KeyVault(VaultName=${azurerm_key_vault.main.name};SecretName=sql-connection-string)"
}
identity {
type = "SystemAssigned"
}
virtual_network_subnet_id = azurerm_subnet.functions.id
tags = {
Environment = "Production"
}
}
# VNet integration subnet
resource "azurerm_subnet" "functions" {
name = "subnet-functions"
resource_group_name = azurerm_resource_group.networking.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.0.10.0/24"]
delegation {
name = "functions-delegation"
service_delegation {
name = "Microsoft.Web/serverFarms"
actions = [
"Microsoft.Network/virtualNetworks/subnets/action"
]
}
}
}
# Private endpoints for storage
resource "azurerm_private_endpoint" "storage_blob" {
name = "pe-storage-blob"
resource_group_name = azurerm_resource_group.functions.name
location = azurerm_resource_group.functions.location
subnet_id = azurerm_subnet.privatelink.id
private_service_connection {
name = "storage-blob-connection"
private_connection_resource_id = azurerm_storage_account.functions.id
is_manual_connection = false
subresource_names = ["blob"]
}
private_dns_zone_group {
name = "storage-dns-group"
private_dns_zone_ids = [azurerm_private_dns_zone.blob.id]
}
}
Comparing Premium vs Consumption
Code to analyze when Premium makes sense:
def calculate_cost_comparison(monthly_executions, avg_duration_ms, memory_gb=1.5):
"""
Compare costs between Consumption and Premium plans.
"""
# Consumption pricing (approximate)
consumption_free_executions = 1_000_000
consumption_free_gb_seconds = 400_000
consumption_exec_cost = 0.20 / 1_000_000 # $0.20 per million executions
consumption_gb_second_cost = 0.000016 # $0.000016 per GB-second
# Premium pricing (EP1)
premium_base_cost = 173 # Monthly base for EP1 (1 instance)
premium_additional_instance = 173 # Per additional instance
# Calculate Consumption cost
billable_executions = max(0, monthly_executions - consumption_free_executions)
total_gb_seconds = (monthly_executions * avg_duration_ms / 1000) * memory_gb
billable_gb_seconds = max(0, total_gb_seconds - consumption_free_gb_seconds)
consumption_cost = (billable_executions * consumption_exec_cost) + \
(billable_gb_seconds * consumption_gb_second_cost)
# Calculate Premium cost (assume 1-2 instances average)
avg_instances = 1.5 # Assume some scaling
premium_cost = premium_base_cost * avg_instances
# Cold start impact (estimated lost revenue/productivity)
cold_start_rate = 0.1 # 10% of requests hit cold start on Consumption
cold_start_delay_seconds = 3
cold_start_cost_per_second = 0.001 # Business cost of delay
consumption_cold_start_cost = monthly_executions * cold_start_rate * \
cold_start_delay_seconds * cold_start_cost_per_second
return {
"consumption": {
"compute_cost": round(consumption_cost, 2),
"cold_start_cost": round(consumption_cold_start_cost, 2),
"total_cost": round(consumption_cost + consumption_cold_start_cost, 2)
},
"premium": {
"compute_cost": round(premium_cost, 2),
"cold_start_cost": 0,
"total_cost": round(premium_cost, 2)
},
"recommendation": "Premium" if premium_cost < (consumption_cost + consumption_cold_start_cost) else "Consumption",
"savings": round(abs(premium_cost - (consumption_cost + consumption_cold_start_cost)), 2)
}
# Analyze different scenarios
scenarios = [
{"name": "Low volume", "executions": 100_000, "duration": 500},
{"name": "Medium volume", "executions": 5_000_000, "duration": 500},
{"name": "High volume", "executions": 50_000_000, "duration": 200},
{"name": "Long running", "executions": 1_000_000, "duration": 5000},
]
print("Cost Comparison Analysis")
print("=" * 60)
for scenario in scenarios:
result = calculate_cost_comparison(
scenario["executions"],
scenario["duration"]
)
print(f"\n{scenario['name']}:")
print(f" Monthly executions: {scenario['executions']:,}")
print(f" Avg duration: {scenario['duration']}ms")
print(f" Consumption: ${result['consumption']['total_cost']}")
print(f" Premium: ${result['premium']['total_cost']}")
print(f" Recommendation: {result['recommendation']}")
VNet-Connected Function
Access private resources from Premium functions:
using System;
using System.Data.SqlClient;
using System.Threading.Tasks;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
public class PrivateResourceFunction
{
private readonly ILogger<PrivateResourceFunction> _logger;
private readonly string _sqlConnectionString;
public PrivateResourceFunction(
ILogger<PrivateResourceFunction> logger,
IConfiguration configuration)
{
_logger = logger;
_sqlConnectionString = configuration["SqlConnectionString"];
}
[Function("ProcessPrivateData")]
public async Task<string> Run(
[QueueTrigger("private-queue", Connection = "StorageConnection")] string message)
{
_logger.LogInformation("Processing message from private queue");
// Connect to private SQL Server via VNet
using var connection = new SqlConnection(_sqlConnectionString);
await connection.OpenAsync();
using var command = new SqlCommand(
"INSERT INTO ProcessedMessages (Content, ProcessedAt) VALUES (@Content, @ProcessedAt)",
connection);
command.Parameters.AddWithValue("@Content", message);
command.Parameters.AddWithValue("@ProcessedAt", DateTime.UtcNow);
await command.ExecuteNonQueryAsync();
_logger.LogInformation("Message processed and stored in private SQL");
return "Processed";
}
}
Scaling Configuration
Configure Premium plan scaling:
from azure.mgmt.web import WebSiteManagementClient
web_client = WebSiteManagementClient(credential, subscription_id)
def configure_premium_scaling(resource_group, function_app_name, min_instances, max_burst):
"""Configure scaling for Premium function app."""
# Get current site config
site_config = web_client.web_apps.get_configuration(
resource_group,
function_app_name
)
# Update scaling settings
site_config.pre_warmed_instance_count = min_instances
site_config.minimum_elastic_instance_count = min_instances
web_client.web_apps.update_configuration(
resource_group,
function_app_name,
site_config
)
# Configure auto-scale rules
from azure.mgmt.monitor import MonitorManagementClient
monitor_client = MonitorManagementClient(credential, subscription_id)
autoscale_setting = {
"location": "eastus",
"profiles": [{
"name": "DefaultProfile",
"capacity": {
"minimum": str(min_instances),
"maximum": str(max_burst),
"default": str(min_instances)
},
"rules": [
{
"metricTrigger": {
"metricName": "FunctionExecutionCount",
"metricResourceUri": f"/subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.Web/sites/{function_app_name}",
"timeGrain": "PT1M",
"statistic": "Average",
"timeWindow": "PT5M",
"timeAggregation": "Average",
"operator": "GreaterThan",
"threshold": 1000
},
"scaleAction": {
"direction": "Increase",
"type": "ChangeCount",
"value": "1",
"cooldown": "PT5M"
}
},
{
"metricTrigger": {
"metricName": "FunctionExecutionCount",
"metricResourceUri": f"/subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.Web/sites/{function_app_name}",
"timeGrain": "PT1M",
"statistic": "Average",
"timeWindow": "PT10M",
"timeAggregation": "Average",
"operator": "LessThan",
"threshold": 100
},
"scaleAction": {
"direction": "Decrease",
"type": "ChangeCount",
"value": "1",
"cooldown": "PT10M"
}
}
]
}],
"enabled": True,
"targetResourceUri": f"/subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.Web/serverFarms/{plan_name}"
}
monitor_client.autoscale_settings.create_or_update(
resource_group,
f"{function_app_name}-autoscale",
autoscale_setting
)
print(f"Configured scaling: min={min_instances}, max={max_burst}")
# Configure scaling
configure_premium_scaling("rg-functions", "myfunc-premium", min_instances=2, max_burst=10)
When to Choose Premium
Decision criteria for Premium plan:
def recommend_plan(requirements):
"""Recommend Consumption or Premium based on requirements."""
reasons_for_premium = []
reasons_for_consumption = []
# VNet connectivity required
if requirements.get("vnet_required"):
reasons_for_premium.append("VNet integration needed for private resources")
# Cold start sensitivity
if requirements.get("cold_start_sensitive"):
reasons_for_premium.append("Application requires consistent response times (no cold starts)")
# Long running functions
if requirements.get("max_duration_minutes", 5) > 10:
reasons_for_premium.append(f"Functions run longer than 10 minutes ({requirements['max_duration_minutes']} min)")
# High memory requirements
if requirements.get("memory_gb", 1.5) > 1.5:
reasons_for_premium.append(f"Requires more than 1.5GB memory ({requirements['memory_gb']}GB)")
# Predictable workload
if requirements.get("predictable_baseline"):
reasons_for_premium.append("Predictable baseline workload benefits from reserved capacity")
# Low volume
if requirements.get("monthly_executions", 0) < 1_000_000:
reasons_for_consumption.append("Low volume workload fits within free tier")
# Highly variable
if requirements.get("highly_variable") and not requirements.get("cold_start_sensitive"):
reasons_for_consumption.append("Highly variable workload benefits from scale-to-zero")
# Cost sensitive
if requirements.get("cost_sensitive") and not reasons_for_premium:
reasons_for_consumption.append("Consumption plan has lower baseline cost")
recommendation = "Premium" if len(reasons_for_premium) > len(reasons_for_consumption) else "Consumption"
return {
"recommendation": recommendation,
"premium_reasons": reasons_for_premium,
"consumption_reasons": reasons_for_consumption
}
# Example evaluation
requirements = {
"vnet_required": True,
"cold_start_sensitive": True,
"max_duration_minutes": 15,
"memory_gb": 2,
"monthly_executions": 5_000_000,
"predictable_baseline": True
}
result = recommend_plan(requirements)
print(f"Recommendation: {result['recommendation']}")
print(f"Premium reasons: {result['premium_reasons']}")
print(f"Consumption reasons: {result['consumption_reasons']}")
Conclusion
Azure Functions Premium plan is the right choice when you need VNet connectivity, cannot tolerate cold starts, have long-running functions, or require more powerful instances. While it has a higher baseline cost than Consumption, the predictable pricing and enhanced capabilities often justify the investment for production workloads.
Evaluate your specific requirements around latency, connectivity, execution time, and cost to determine the best plan. Many organizations use both plans: Consumption for low-priority background tasks and Premium for customer-facing, latency-sensitive functions.