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 }}
  

Azure Functions scale from simple webhooks to enterprise orchestration with Durable Functions.