Introduction
Azure Functions accelerates event-driven development by abstracting infrastructure so you can focus on code. This guide moves from a minimal HTTP trigger to an enterprise-ready architecture with durable orchestrations, secure secret management, observability, automation pipelines, and cost/performance tuning.
You will learn:
- Core concepts: triggers, bindings, function app lifecycle
- Choosing hosting plans (Consumption, Premium, Dedicated, Container Apps)
- Implementing HTTP, Timer, Queue, Service Bus, Event Grid, Blob triggers
- Durable Functions orchestration & state management patterns
- Integration with Key Vault, Storage, Cosmos DB, Event Grid
- Security (Managed Identity, Entra ID auth, network isolation)
- Monitoring (Application Insights + OpenTelemetry)
- Scaling & cost optimization strategies
- CI/CD with GitHub Actions
- Troubleshooting and resiliency patterns
Time to Read: 60–90 minutes
Skill Level: Beginner → Intermediate
Architecture Overview
flowchart LR
subgraph Client
APIClient[API Consumers]
Portal[Admin Portal]
end
subgraph Ingress
HTTP[HTTP Trigger]
EventGrid[Event Grid Trigger]
Timer[Timer Trigger]
Queue[Queue Trigger]
ServiceBus[Service Bus Trigger]
Blob[Blob Trigger]
end
subgraph FuncApp[Function App]
Func1[ProcessOrder]
Func2[GenerateReport]
Orchestrator[Durable Orchestrator]
Activity1[Validate]
Activity2[Enrich]
Activity3[Persist]
end
subgraph Services[Azure Services]
KV[(Key Vault)]
Cosmos[(Cosmos DB)]
Storage[(Blob Storage)]
SB[(Service Bus)]
AI[(App Insights)]
end
Client --> HTTP
EventGrid --> Func1
Queue --> Func2
ServiceBus --> Orchestrator
Blob --> Func2
HTTP --> Orchestrator
Orchestrator --> Activity1
Orchestrator --> Activity2
Orchestrator --> Activity3
Activity3 --> Cosmos
Activity2 --> Storage
Func1 --> SB
Func2 --> KV
FuncApp --> AI
Prerequisites
| Requirement | Details |
|---|---|
| Subscription | Azure subscription with permissions to create resource group |
| Tools | Azure CLI, VS Code, Node.js or .NET SDK, GitHub CLI |
| Accounts | Entra ID user with contributor role, GitHub account for CI/CD |
| Monitoring | Application Insights workspace or direct component creation |
Install tooling:
winget install Microsoft.AzureCLI
winget install Microsoft.VisualStudioCode
winget install Git.Git
Step-by-Step Implementation
1. Resource Group & Core Services
az group create --name rg-func-intro --location eastus
az storage account create --name funcintrostore --resource-group rg-func-intro --sku Standard_LRS
az monitor app-insights component create --app func-intro-ai --location eastus --resource-group rg-func-intro --application-type web
2. Create Function App (Consumption)
az functionapp create --resource-group rg-func-intro --consumption-plan-location eastus --runtime dotnet --functions-version 4 --name func-intro-app --storage-account funcintrostore --app-insights func-intro-ai
3. Add Managed Identity & Key Vault
az keyvault create --name kv-func-intro --resource-group rg-func-intro --location eastus
az functionapp identity assign --name func-intro-app --resource-group rg-func-intro
$principalId = az functionapp identity show -g rg-func-intro -n func-intro-app --query principalId -o tsv
az keyvault set-policy -n kv-func-intro --object-id $principalId --secret-permissions get list
4. Sample HTTP Trigger (C#)
public static class HttpHello
{
[FunctionName("HttpHello")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "hello")] HttpRequest req,
ILogger log)
{
log.LogInformation("Processing HttpHello request");
var name = req.Query["name"];
return new OkObjectResult(new { message = $"Hello {name}" });
}
}
5. Timer Trigger (Maintenance)
public static class NightlyMaintenance
{
[FunctionName("NightlyMaintenance")]
public static async Task Run([TimerTrigger("0 0 2 * * *")]TimerInfo timer, ILogger log)
{
log.LogInformation("Nightly maintenance started");
// purge temp blobs / archive logs
await Task.Delay(250);
log.LogInformation("Nightly maintenance complete");
}
}
6. Durable Orchestration Pattern
public static class OrderOrchestrator
{
[FunctionName("OrderOrchestrator")]
public static async Task<object> Run([OrchestrationTrigger] IDurableOrchestrationContext ctx)
{
var order = ctx.GetInput<Order>();
var valid = await ctx.CallActivityAsync<bool>("ValidateOrder", order);
if(!valid) return new { status = "Rejected" };
var enriched = await ctx.CallActivityAsync<Order>("EnrichOrder", order);
await ctx.CallActivityAsync("PersistOrder", enriched);
await ctx.CallActivityAsync("NotifyQueue", enriched.Id);
return new { status = "Completed", id = enriched.Id };
}
}
7. Local Development & Debugging
func init src --dotnet
cd src
func new --name HttpHello --template "HTTP trigger" --authlevel Function
func start
Browse http://localhost:7071/api/hello?name=Azure.
Security & Identity
| Aspect | Best Practice | Implementation |
|---|---|---|
| Secrets | Use Key Vault + Managed Identity | Azure.Identity client + secret retrieval |
| Auth Level | Avoid Anonymous unless public webhook | Use Function or User level |
| Network | Private endpoints for Premium / VNet integration | App Service VNet integration |
| Principle of Least Privilege | Separate function apps by domain | Resource group & identity isolation |
| Data Access | Use role assignments not connection strings | RBAC on Storage, Cosmos DB |
Key Vault retrieval example (C#):
var client = new SecretClient(new Uri(Environment.GetEnvironmentVariable("KEY_VAULT_URI")), new DefaultAzureCredential());
var secret = client.GetSecret("ApiKey").Value.Value;
Monitoring & Telemetry
Enable logging & traces:
builder.Services.AddLogging();
// For isolated process, configure host.json + app insights connection string
Kusto query (failed functions):
requests
| where cloud_RoleName == "func-intro-app"
| where success == false
| summarize count() by operation_Name, bin(timestamp, 1h)
Performance & Cost Optimization
| Strategy | Applies To | Benefit |
|---|---|---|
| Bundle Functions by domain | All | Reduced cold start variance |
| Use async I/O | HTTP / Queue | Lower thread usage |
| Avoid heavy static constructors | All | Faster warm / scale |
| Durable fan-out/fan-in | Orchestrations | Parallel efficiency |
| Premium plan for steady load | High throughput workloads | Predictable performance |
| Caching configuration | HTTP | Less Key Vault latency |
CI/CD Pipeline
name: deploy-azure-functions
on:
push:
paths: [ 'src/**' ]
branches: [ main ]
jobs:
build-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Build
run: dotnet build src/FunctionApp.csproj -c Release
- name: Publish
run: dotnet publish src/FunctionApp.csproj -c Release -o publish
- name: Azure Login
uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Deploy
uses: azure/functions-action@v1
with:
app-name: func-intro-app
package: publish
Troubleshooting Matrix
| Symptom | Cause | Diagnosis | Resolution |
|---|---|---|---|
| Cold starts | Infrequent invocations | App Insights startup trace | Warmup ping or Premium plan |
| 401 errors | Missing function key | Check Host keys |
Regenerate & update client |
| Failed durable instances | Activity exception | DurableFunctionsHubHistory table |
Retry pattern / circuit breaker |
| Storage throttling | High concurrency | Metrics: Storage transactions | Upgrade tier / optimize batching |
| Secret retrieval latency | Frequent calls to Key Vault | App Insights dependency timing | Cache secret until expiry window |
Resiliency Patterns
- Retries with exponential backoff for transient external calls.
- Circuit breaker around enrichment APIs.
- Poison queue handling: move failed messages to dead-letter queue and alert.
Image References


