Skip to main content

Command Palette

Search for a command to run...

Azure Functions — A Developer’s Guide

Updated
11 min read

What are Azure Functions?

Azure Functions is Microsoft’s serverless compute platform that lets you run small pieces of code (“functions”) without managing servers, VMs, or containers. As a developer, you focus purely on the logic — Azure takes care of hosting, scaling, patching, and infrastructure behind the scenes.

One of the biggest advantages of Azure Functions is how they help you lighten your main application. Instead of keeping everything inside a single API or service, you can decouple specific pieces of logic into small, independent functions. These functions can run asynchronously and fit naturally into event‑driven, pub‑sub architectures

A simple metal model:

💡
Azure Functions are event‑driven micro‑functions that wake up, do one job, and go back to sleep.

This makes them perfect for modern cloud‑native systems where you want clean boundaries, minimal overhead, and automatic scaling without operational noise.

Why we as developers should use Azure Functions?

As Developers we could adapt Azure Functions to gain below benefits:

  • No infrastructure management
    No servers, no containers, no patching. Azure takes care of hosting and runtime for you.

  • Automatic scaling
    Functions scale up and down based on demand. Whether you get 10 requests or 10,000, Azure scales automatically.

  • Pay only for what you use
    On the Consumption plan, you’re billed per execution. If your function doesn’t run, you don’t pay.

  • Deep integration with Azure services
    Functions plug directly into Service Bus, Event Grid, Cosmos DB, Blob Storage, and more — with almost no boilerplate.

  • Perfect for asynchronous and event‑driven workflows
    This lets you offload heavy or background logic from your main API, making your core application lighter and more responsive.

💡
If you want to build modern, cloud‑native systems without drowning in infrastructure overhead, Azure Functions is one of the best places to start.

When to Use Azure Functions?

Azure Functions shine in scenarios where something happens and you need code to respond. They fit naturally into event‑driven, asynchronous, cloud‑native workflows. Here are the most common (and practical) use cases:

✔ Event‑driven processing

Perfect when an external event should trigger a piece of logic:

  • Blob uploaded → resize or validate the file

  • Queue message → process an order or background task

  • Event Grid event → react to side effects in your system

This is where Functions feel the most natural.

✔ Lightweight APIs

Azure Functions can also act as small, focused HTTP endpoints:

  • Quick HTTP APIs

  • Webhooks

  • Slack/Teams integrations

Great for scenarios where you don’t need a full-blown API project.

✔ Background jobs

Functions are ideal for scheduled or recurring tasks:

  • Timer-triggered jobs

  • Cleanup routines

  • Maintenance tasks

  • Daily/weekly summaries

No need for cron servers or background worker services.

✔ Decoupling logic from your main app

You can offload heavy or asynchronous logic from your API into Functions:

  • Long-running tasks

  • Notification pipelines

  • Data processing

  • Integrations

This keeps your main application lighter, faster, and easier to maintain.

💡
Whenever you have a small, focused piece of logic that should run because something happened, Azure Functions are usually the right tool.

How Azure Functions Work?

The simplest way to understand Azure Functions is to imagine a worker who sleeps when there’s nothing to do.
When something happens — an event, a message, a file upload — that worker gets triggered, wakes up, completes the job, and goes back to sleep until the next request arrives.

This is the core idea behind Azure Functions:

💡
They wake up when triggered, execute a single piece of logic, and then scale back down when idle.

So what are these Triggers that Azure Functions wake up to?

Triggers are the events that cause a Function to run.
Azure provides a wide range of built‑in triggers so your Function can react to almost anything happening inside your system.

Common triggers include:

  • HTTP requests
    (e.g., lightweight APIs, webhooks)

  • Timer schedules
    (e.g., daily jobs, cleanup tasks)

  • Blob uploads
    (e.g., process a file when it lands in storage)

  • Queue messages
    (e.g., background processing)

  • Service Bus messages
    (e.g., domain events like TaskAssigned)

  • Cosmos DB change feed
    (e.g., react to inserts/updates in a container)

  • Event Grid events
    (e.g., system events, custom events, resource changes)

Bindings

Bindings allow Azure Functions to connect to other Azure resources in a simple, declarative way — without writing a ton of boilerplate code. They make it easy to read from or write to external services during a Function’s execution.

Instead of manually creating SDK clients, handling authentication, or wiring up plumbing code, you simply declare the binding in your function signature and Azure takes care of the rest.

Azure Functions support two main types of bindings:

Input Bindings

Input bindings let your Function read data from another Azure resource.

For example:
If your Function needs to read a file from Blob Storage or fetch a document from Cosmos DB, you can declare an Input Binding. Azure will automatically pass that resource into your Function as a parameter.

This keeps your code clean and focused on logic, not infrastructure.

Output Bindings

Output bindings let your Function write data to another Azure resource.

For example:
If your Function needs to write a document into a Cosmos DB container or upload a file to Blob Storage, you can declare an Output Binding. Azure will handle the write operation for you.

Again — no SDK setup, no connection management, no boilerplate.

📌 Simple Example: HTTP Trigger → Read from Blob → Write to Queue

This example does three things:

  1. Trigger: Runs when someone calls an HTTP endpoint

  2. Input Binding: Reads a text file from Blob Storage

  3. Output Binding: Sends a message to a Queue

Where Do we Store Configurations in Azure Functions?

Local Development

When running Functions locally, you store your settings in a file called: local.settings.json

Production

In production, you typically split your configuration into two categories.

Non Secret Values

These are non‑secret values such as:

  • Feature flags

  • Environment names

  • API base URLs

  • Logging levels

  • Toggle values

  • Any non-sensitive config

These live in:

Azure Portal → Function App → Settings → Environment Variables

Azure injects them as environment variables at runtime.

Secret Values

Secrets include:

  • Connection strings

  • API keys

  • Access tokens

  • Private keys

  • Sensitive URLs

  • Anything you wouldn’t commit to Git

These should never be stored directly in Function App settings.

Instead, you:

  1. Store the secret in Azure Key Vault

  2. Enable Managed Identity on the Function App

  3. Use a Key Vault reference inside Function App Environment Variables

This way:

  • The Function App never stores the secret

  • The secret rotates safely

  • Access is controlled via Azure AD

  • No secrets appear in logs, code, or CI/CD pipelines

Hosting Plans

Azure Functions can run on 3 hosting plans.

Plan Suitable for Details
Consumption Event Driven Workloads Auto-Scales based on demand, We pay-per-executions, cold starts possible and has 230 second timeout
Premium High Performance Scenarios with no cold starts They are always warmed up, allows Azure VNet support, usually good for long running operations, does not have 230 seconds timeout
Dedicated This is ideal when Functions are part of a larger App Service‑based architecture. Azure Function is hosted on your existing App Service Plan, Always on, no cold starts

As a rule of thumb we can start with Consumption plan and based on the load we can always move into Premium or Dedicated plans.

Common Pitfalls

Even though Azure Functions are powerful and developer‑friendly, there are a few common pitfalls to be aware of — especially when running on the Consumption plan.

1. Cold Starts on the Consumption Plan

If your Function isn’t triggered frequently, it may go idle.
The first request after an idle period can experience a cold start, which adds noticeable latency.

This mainly affects:

  • HTTP-triggered functions

  • Functions with large dependencies

  • Functions deployed in regions far from the caller

Premium and Dedicated plans eliminate cold starts.

2. 230‑Second Timeout for HTTP Functions (Consumption Plan)

On the Consumption plan, HTTP-triggered functions have a hard timeout of ~230 seconds.

If your operation is long‑running, you should:

  • Move the logic into a Durable Function, or

  • Use an asynchronous workflow (publish a message to Queue/Service Bus and process it in the background)

This keeps your API responsive and avoids timeouts.

3. Built‑in Retry Policies

Azure Functions automatically retry failed executions depending on the trigger type.

For example:

  • Queue and Service Bus triggers retry multiple times

  • Event Grid retries with exponential backoff

  • HTTP triggers do not retry automatically

Developers often wonder:

“Can we use Polly retry policies inside Azure Functions?”

You can, but it’s usually unnecessary because the platform already handles retries for you.
Polly is more useful inside your business logic (e.g., retrying an external API call), not for retrying the Function itself.

4. Use Durable Functions for Complex Orchestration

If your workflow needs:

  • Fan‑out / fan‑in

  • Chaining multiple steps

  • Waiting for external events

  • Long‑running stateful operations

Then Durable Functions is the right tool.

Trying to implement these patterns manually inside a normal Function often leads to complexity, timeouts, or inconsistent state.

Real World Example

📌Scenario

When a manager assigns a task to a Team member:

  1. The API (Domain Event Handler class) publishes a lightweight TaskAssigned message (with TaskId only) to a Service Bus Topic.

  2. The API (Domain Event Handler class) also writes a full assignment record into Cosmos DB → TaskAssigned container.

  3. An Azure Function reacts to the Service Bus message, fetches the full record from Cosmos DB, and publishes a TaskAssignedNotification event to Event Grid for Fan Out.

  4. Downstream systems (UI dashboards, notifications, analytics) react to the Event Grid event.

📌Trigger

Service Bus Topic Trigger

The Azure Function is triggered when a new message arrives in the TaskAssigned topic.

Why Service Bus?
Because this is a domain event that must not be lost — Service Bus guarantees delivery, retries, and durability.

📌Input Binding

Cosmos DB Input Binding

The Function reads the full task assignment record from:

  • Cosmos DB TaskAssigned Container

The record contains:

  • taskId

  • assignedUserId

  • assignedByManagerId

  • timestamps

  • metadata

This avoids passing large payloads through Service Bus and keeps the message lightweight.

📌Output Binding

Event Grid Output Binding

The Function publishes a new event:

eventType: TaskAssignedNotification
subject: /tasks/{taskId}
data: { taskId, assignedUserId, assignedByManagerId, timestamp }

Why Event Grid?
Because it enables fan-out to multiple consumers:

  • Real-time UI updates (via SignalR)

  • Email/SMS notifications

  • Teams/Slack messages

  • Analytics pipelines

  • Audit logs

  • Mobile app updates

No changes to the Function are needed when new consumers are added.

📌Example (C#)

public static class TaskAssignedNotificationFunction
{
    [FunctionName("TaskAssignedNotificationFunction")]
    public static async Task Run(
        // 1️⃣ Trigger: Fired when a message arrives in the Service Bus Topic
        [ServiceBusTrigger("task-assigned", "notification-sub", Connection = "ServiceBusConnection")]
        TaskAssignedMessage message,

        // 2️⃣ Input Binding: Fetch the full assignment record from Cosmos DB
        //     - Uses the TaskId from the Service Bus message
        [CosmosDB(
            databaseName: "devpulse",
            containerName: "TaskAssigned",
            Connection = "CosmosDbConnection",
            Id = "{taskId}",
            PartitionKey = "{taskId}")]
        TaskAssignmentRecord assignment,

        // 3️⃣ Output Binding: Publish a new event to Event Grid
        [EventGrid(TopicEndpointUri = "EventGridTopicUri", TopicKeySetting = "EventGridKey")]
        IAsyncCollector<EventGridEvent> eventGridOutput,

        ILogger log)
    {
        // Log the start of processing
        log.LogInformation($"Processing TaskAssigned event for TaskId: {message.TaskId}");

        // Build the event payload that will be sent to Event Grid
        var notificationEvent = new EventGridEvent(
            subject: $"task/{assignment.TaskId}",              // Logical grouping of events
            eventType: "TaskAssignedNotification",             // Custom event type
            data: new {
                assignment.TaskId,
                assignment.AssignedUserId,
                assignment.AssignedByManagerId,
                assignment.Timestamp
            },
            dataVersion: "1.0"
        );

        // Publish the event to Event Grid
        await eventGridOutput.AddAsync(notificationEvent);

        // Log completion
        log.LogInformation($"TaskAssignedNotification published for TaskId: {assignment.TaskId}");
    }
}

Summary

Azure Functions is one of the easiest ways to build event-driven, serverless applications on Azure. It removes infrastructure overhead, scales automatically, and integrates deeply with Azure services.

If you’re building modern cloud-native systems — Functions should be in your toolkit.