Azure Functions is a serverless compute service that runs event-driven code without managing infrastructure. Functions scale automatically from zero to thousands of instances and you pay only for execution time and resources consumed. It integrates natively with Azure Storage, Service Bus, Event Hubs, Cosmos DB, and hundreds of other services.

How Functions Work

A function app consists of:

  • Trigger: Event that invokes the function (HTTP, queue message, timer, blob upload)
  • Bindings: Declarative connections to input/output data sources without boilerplate SDK code
  • Host: Runtime that manages scaling, concurrency, and health

The Flex Consumption plan (2024+) offers faster cold starts and optional always-ready instances while keeping serverless billing.

Hosting Plans

Plan Scaling Cold Start VNet Use Case
Consumption Auto, pay per execution Seconds No Most event-driven workloads
Flex Consumption Auto, per-second billing Faster Optional Production serverless
Premium Pre-warmed instances Minimal Yes Low-latency, long-running
Dedicated (App Service) Manual/auto on ASP None Yes Predictable workloads
Container Apps KEDA-based Low Yes Containerized functions

Create an HTTP Trigger Function

  # Install Core Tools
brew tap azure/functions
brew install azure-functions-core-tools@4

# Create project (Node.js v4 programming model)
func init MyFunctionApp --worker-runtime node --model V4
cd MyFunctionApp
func new --name HttpHello --template "HTTP trigger"

# Local run with storage emulator
func start
  

Example function (src/functions/HttpHello.js):

  const { app } = require('@azure/functions');

app.http('HttpHello', {
  methods: ['GET', 'POST'],
  authLevel: 'function',
  handler: async (request, context) => {
    const name = request.query.get('name') || 'World';
    context.log(`Processing request for: ${name}`);
    return { status: 200, jsonBody: { message: `Hello, ${name}!` } };
  }
});
  

Deploy to Azure

  # Create storage account (required for Functions runtime state)
az storage account create \
  --name stfuncprod001 \
  --resource-group rg-webapp-prod \
  --location eastus \
  --sku Standard_LRS

# Create Function App on Consumption plan
az functionapp create \
  --resource-group rg-webapp-prod \
  --consumption-plan-location eastus \
  --runtime node \
  --runtime-version 20 \
  --functions-version 4 \
  --name func-webapp-prod \
  --storage-account stfuncprod001 \
  --os-type Linux

# Enable Application Insights
az monitor app-insights component create \
  --app ai-func-prod \
  --location eastus \
  --resource-group rg-webapp-prod \
  --application-type web \
  --kind web

az functionapp config appsettings set \
  --name func-webapp-prod \
  --resource-group rg-webapp-prod \
  --settings APPLICATIONINSIGHTS_CONNECTION_STRING="<connection-string>"

func azure functionapp publish func-webapp-prod
  

Common Triggers and Bindings

Trigger Binding Output Use Case
HTTP HTTP response REST APIs, webhooks
Timer Scheduled jobs (NCRONTAB syntax)
Blob Blob output Process uploaded files
Queue Storage Queue output Decouple with message queues
Service Bus Service Bus output Enterprise messaging
Event Hub Event Hub output Stream processing
Cosmos DB Cosmos DB output React to database changes

Queue trigger example (function.json v1 style for reference):

  {
  "bindings": [
    {
      "name": "msg",
      "type": "serviceBusTrigger",
      "direction": "in",
      "queueName": "orders",
      "connection": "ServiceBusConnection"
    }
  ]
}
  

Durable Functions

For workflows with state, retries, and orchestration across multiple functions:

  const df = require('durable-functions');

df.app.orchestration('orderOrchestrator', function* (context) {
  const order = context.df.getInput();
  const inventory = yield context.df.callActivity('checkInventory', order);
  if (!inventory.available) {
    yield context.df.callActivity('notifyBackorder', order);
    return { status: 'backordered' };
  }
  yield context.df.callActivity('processPayment', order);
  yield context.df.callActivity('shipOrder', order);
  return { status: 'shipped' };
});
  

Durable Functions persist orchestration state in Azure Storage or Netherite (Premium plan) — ideal for long-running approval workflows and fan-out/fan-in patterns.

Real-World Scenario: Image Processing Pipeline

Component Configuration
Trigger Blob upload to uploads/ container
Processing Resize, watermark, generate thumbnails
Output Write to processed/ container; queue notification
Plan Premium (VNet access to private storage)
Scaling Max 200 concurrent instances; batch size 16
Monitoring App Insights dependency tracking; alert on failure rate > 1%

Functions vs Alternatives

Feature Azure Functions Logic Apps Container Apps
Code Full code (multi-language) Low-code workflows Container images
Complexity Simple to moderate Integration-focused Microservices
Pricing Per execution Per action Per vCPU-second
Stateful workflows Durable Functions Built-in External store
Best for Event-driven code B2B integrations Long-running services

Common Mistakes

  1. Secrets in app settings as plaintext — use Key Vault references
  2. No dead-letter handling — poison messages loop forever on queue triggers
  3. Monolithic function apps — split by domain for independent scaling
  4. Ignoring timeout limits — Consumption max 5 min (configurable to 10); Premium up to unlimited
  5. Missing idempotency — retries cause duplicate processing without deduplication
  6. Cold start in latency-sensitive APIs — use Premium or Flex Consumption with always-ready

Troubleshooting

Issue Diagnosis Fix
Function not triggering Wrong connection string or trigger config Verify app settings; check Storage queue/blob exists
401 on HTTP trigger Missing or wrong function key Pass ?code=<key> or set authLevel: anonymous for public APIs
Timeout errors Processing exceeds limit Move to Premium plan; optimize code; use Durable Functions
High memory usage Large payloads loaded entirely Stream blob data; process in chunks
Deployment succeeds but 404 Wrong runtime stack Match --runtime and --functions-version to project
  # Stream live logs
func azure functionapp logstream func-webapp-prod

# List function keys
az functionapp function keys list \
  --name func-webapp-prod \
  --resource-group rg-webapp-prod \
  --function-name HttpHello
  

Best Practices

  • Keep functions small and focused — one responsibility per function
  • Use Managed Identity instead of connection strings where supported
  • Set retry policies and dead-letter queues for queue/Service Bus triggers
  • Configure max concurrent requests to protect downstream dependencies
  • Monitor with Application Insights — track duration, failures, dependencies
  • Use deployment slots on Premium/Dedicated plans for zero-downtime releases
  • Store configuration in App Configuration for feature flags and settings

Next: Azure Monitor.