Azure Functions Best Practices
Production Azure Functions — scaling, deployment slots, monitoring, cold starts, and security on Azure.
Running Azure Functions in production requires configuration beyond func start. These practices ensure reliability and maintainability.
Use the v2 Programming Model
The decorator-based model (function_app.py) is the current standard:
import azure.functions as func
app = func.FunctionApp(http_auth_level=func.AuthLevel.FUNCTION)
@app.route(route="items", methods=["GET", "POST"])
def items(req: func.HttpRequest) -> func.HttpResponse:
...
Avoid the legacy function.json + separate folder structure for new projects.
Optimize Cold Starts
# Initialize outside the function — reused across invocations
import azure.cosmos as cosmos
import logging
cosmos_client = cosmos.CosmosClient.from_connection_string(
os.environ["CosmosDBConnection"]
)
database = cosmos_client.get_database_client("mydb")
container = database.get_container_client("items")
@app.route(route="items/{id}")
def get_item(req: func.HttpRequest) -> func.HttpResponse:
item_id = req.route_params["id"]
item = container.read_item(item=item_id, partition_key=item_id)
return func.HttpResponse(json.dumps(item), mimetype="application/json")
Reduce Package Size
# requirements.txt — minimal dependencies
azure-functions
azure-cosmos
# Avoid: azure-mgmt-* (management SDKs are huge)
Use {function_name}.function.json scriptFile with remote build on Linux for native dependencies.
Configure host.json
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"maxTelemetryItemsPerSecond": 20
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[4.*, 5.0.0)"
},
"functionTimeout": "00:05:00",
"concurrency": {
"dynamicConcurrencyEnabled": true,
"maximumFunctionConcurrency": 100
}
}
Deployment Slots
Use slots for zero-downtime deployments:
# Create staging slot
az functionapp deployment slot create \
--name my-function-app --resource-group my-rg --slot staging
# Deploy to staging
func azure functionapp publish my-function-app --slot staging
# Swap to production
az functionapp deployment slot swap \
--name my-function-app --resource-group my-rg \
--slot staging --target-slot production
Application Insights Monitoring
Enable Application Insights for every production function app:
az monitor app-insights component create \
--app my-function-app-insights --resource-group my-rg
Query logs in Application Insights:
traces
| where timestamp > ago(1h)
| where severityLevel >= 3
| order by timestamp desc
Track custom metrics:
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
@app.route(route="process")
def process(req):
with tracer.start_as_current_span("process_request"):
result = do_work()
return func.HttpResponse(str(result))
Managed Identity (No Connection Strings)
Prefer managed identity over connection strings in production:
from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient
credential = DefaultAzureCredential()
blob_service = BlobServiceClient(
account_url="https://mystorageaccount.blob.core.windows.net",
credential=credential,
)
Grant the function app’s identity Storage Blob Data Contributor role on the storage account.
Scaling Configuration
# Consumption plan — auto-scales
az functionapp plan create --name my-plan --resource-group my-rg \
--sku Y1 --is-linux
# Premium plan — pre-warmed instances, VNet support
az functionapp plan create --name my-premium-plan \
--resource-group my-rg --sku EP1 --min-instances 1
| Plan | Cold Start | VNet | Min Instances | Best For |
|---|---|---|---|---|
| Consumption | Yes | No | 0 | Variable traffic |
| Premium | Reduced | Yes | 1+ | Low latency, VNet |
| Dedicated | No | Yes | Fixed | Predictable load |
Security Checklist
- Use Function-level or App Service authentication
- Store secrets in Key Vault with managed identity
- Enable HTTPS only
- Restrict CORS to known origins
- Validate all request input
- Use least-privilege RBAC roles
- Enable diagnostic settings for audit logs
CI/CD with GitHub Actions
name: Deploy Azure Function
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install -r requirements.txt
- run: pip install pytest && pytest tests/
- uses: Azure/functions-action@v1
with:
app-name: my-function-app
package: .
publish-profile: ${{ secrets.AZURE_FUNCTIONAPP_PUBLISH_PROFILE }}
Related Chapters
Azure Functions scale from simple webhooks to enterprise orchestration with Durable Functions.