Azure Functions: Small Pieces of Code That Wake Up When Something Happens
A beginner-friendly guide to Azure Functions, the serverless service that runs your code in response to events, scales automatically and charges only for what you use, explained step by step with everyday analogies.
Imagine a helpful neighbour who sleeps in the next room. You do not pay the neighbour a monthly salary. Instead, you ring a bell whenever you need something done: water the plants, sign for a parcel, switch on the generator. The neighbour wakes up, does that one job, and goes back to sleep. If ten parcels arrive at once, ten neighbours show up. If nothing happens all night, nobody is paid. Azure Functions works like this bell and these neighbours, except that the neighbours are small pieces of your code.
In this guide we begin with the simple question “what is serverless?”, and slowly build up to triggers, bindings, hosting plans, scaling, Durable Functions, security, monitoring and cost. No earlier knowledge is assumed. Every new word is explained when it first appears, usually with a comparison from daily life. Features, limits and prices evolve, so treat this guide as a map of ideas and confirm specifics in the current Azure documentation.
1What Is Azure Functions?
It is a service for running small units of code in the cloud, triggered by events, without managing servers.
Normally, to run a program in the cloud, you create a server, install software, keep the server running day and night and look after its updates. The program waits for work, and you pay for the server whether work arrives or not. This is wasteful when the work comes only now and then.
Azure Functions offers a different way. You write a small function, which is a piece of code that does one job, such as resizing a picture, processing an order or sending a message. You tell Azure what should start it: a web request, a timer, a new file, a message in a queue or many other events. When the event happens, Azure runs your function. When the work is done, the resources are released. You do not manage servers, and you pay only for the time and resources that your code uses.
This style is called serverless computing. The word does not mean that there are no servers. It means that you do not see or manage them. Azure decides where and how to run your code, and adds or removes capacity automatically as the number of events changes.
Think of the difference between owning a car and using a ride-hailing app. With a car, you pay for parking, servicing and insurance even when it is parked. With the app, you pay only when you travel. Azure Functions is the ride-hailing app for running code.
Words you will meet again and again
Function
A single piece of code that does one job and runs when its trigger fires.
Function App
A container for one or more functions that are deployed, scaled and configured together.
Trigger
The event that makes a function run, such as a web request, a timer or a new message. Every function has exactly one.
Binding
A declared connection to data, such as a queue or a database, so that your code reads or writes it with little plumbing.
Hosting Plan
The choice that decides how your function app scales, how it is billed and which features it has.
Cold Start
The short delay when a function runs after a quiet period and a fresh instance must start first.
2Why Does Azure Functions Exist?
Because a lot of useful work is small, occasional and driven by events.
Think about the tasks that make up a typical business system. When a customer uploads a photo, a thumbnail must be made. When an order is placed, a confirmation email must be sent. Every night, old records must be cleaned up. When a sensor reports a high temperature, an alert must be raised. None of these tasks needs a whole server running all day. Each needs a small piece of code at the right moment.
Building these tasks on traditional servers means paying for idle time, planning capacity for the busiest moment and handling updates and failures yourself. Azure Functions removes this burden so that developers can focus on the logic, and the platform handles the scaling and infrastructure.
Focus on code, not servers
You write the logic, and Azure takes care of provisioning, patching and scaling the machines that run it.
Pay for what you use
With consumption-style plans, there is no charge while nothing is running, which suits spiky and occasional workloads.
Scale automatically
Ten events or ten million, the platform adds instances as needed without manual intervention.
Connect to many services easily
Triggers and bindings link functions to queues, storage, databases and event streams with very little code.
Move fast
A small function can go from idea to running in the cloud within hours, which helps with prototypes and glue code between systems.
Functions are not the best fit for everything. Long-running processes, very chatty applications with heavy shared state, and software that needs full control of the operating system may be better served by other services. We compare the options later in this guide.
3Core Concepts: Functions, Function Apps, Triggers and Bindings
Four simple ideas explain almost everything about how Azure Functions is organised.
Function
The smallest unit. It has a name, some code, one trigger and optionally several bindings. It should do one job well.
Function app
The unit of deployment and scaling. All functions inside one app share the same hosting plan, settings, runtime version and scale instances.
Trigger
The event that starts the function. A function has exactly one trigger. The trigger also passes data into the function, such as the content of a message.
Bindings
Optional, declarative connections. Input bindings bring data in, such as reading a record. Output bindings send data out, such as writing a message to a queue.
flowchart LR
T["Trigger: new message in queue"] --> F["Function: process order"]
IB["Input binding: read customer record"] --> F
F --> OB1["Output binding: write to database"]
F --> OB2["Output binding: send email message"]
A function is like a clerk at a counter. The trigger is the bell on the counter that wakes the clerk. Input bindings are the files placed on the desk for the clerk. Output bindings are the outgoing trays where the clerk puts the results. The function app is the whole office where several clerks work under the same management.
Why bindings matter
Without bindings, your code would need to open connections, handle authentication and manage details for every service it touches. With bindings, you declare what you need, and the runtime does the plumbing. This keeps functions short and focused. Bindings are optional, and you can always use the standard software libraries of a service directly when you need more control.
Putting many unrelated functions into one function app because it is convenient. They then share scaling, settings and failures, and a noisy function can starve the others. Group functions that belong together and have similar scaling needs, and separate the rest.
4Inside the Machine: How Functions Actually Run
A look behind the curtain explains scaling, cold starts and many surprises.
Each function app runs on one or more instances. An instance is a virtual machine or container that hosts the Functions runtime, which is called the host, together with your code. The host listens for trigger events, calls your function with the event data, handles bindings and reports results and logs.
A separate component, the scale controller, watches the event sources of your function app. For example, it looks at the length of a queue or the lag of an event stream. When it sees more work than the current instances can handle, it adds instances. When work decreases, it removes them. On plans that scale to zero, it can stop all instances when there is nothing to do and start one when an event appears.
Functions Host
The runtime that listens for triggers, invokes your code, manages bindings and sends telemetry.
Language Worker
The process that runs your code in its own language, communicating with the host. In the recommended .NET model, it runs separately from the host.
Scale Controller
The platform component that watches event sources and decides how many instances should run.
Storage Account
Used by the host for internal bookkeeping such as keys, leases, timer state and checkpoints. A function app needs one.
An event occurs
A message arrives in a queue, a file is uploaded, a timer fires or a web request comes in.
The scale controller notices
If no instance is running, or if existing ones are busy, it arranges for instances to start.
The host starts and loads your code
A new instance starts the host and the language worker and loads your function app. This is the cold start.
The trigger delivers the event
The host reads the event, prepares input bindings and invokes your function with the data.
Your code runs
The function does its work, using output bindings or libraries to write results.
Completion is recorded
The host marks the event as processed, for example by deleting the queue message, and reports telemetry.
sequenceDiagram
participant S as Event Source
participant C as Scale Controller
participant H as Functions Host Instance
participant F as Your Function Code
participant O as Output Service
S->>C: New events waiting
C->>H: Start or add instance
H->>S: Read event
H->>F: Invoke with event data
F->>O: Write result
F-->>H: Finished
H->>S: Mark event as processed
A taxi dispatcher watches the number of waiting passengers and sends more cars when the queue grows. Each car has a driver, which is the host, who reads the destination and drives the route, which is your code. When passengers stop coming, cars are sent home.
Because the host stores keys, timer schedules, leases and checkpoints in the storage account, problems with that account can break your function app. Use a dedicated, healthy storage account in the same region, and prefer identity-based access instead of shared keys where supported.
5Triggers and Bindings in Practice
The list of triggers is the best way to see what Functions can do for you.
| Trigger | Fires when | Typical use |
|---|---|---|
| HTTP | A web request arrives | APIs, webhooks and small web back ends |
| Timer | A schedule is reached | Nightly clean-up, reports, periodic checks |
| Queue storage | A message appears in a storage queue | Simple background work |
| Service Bus | A message arrives in a queue or topic | Reliable business messaging with ordering and dead-letter support |
| Event Hubs | Events arrive in a stream | Telemetry and high-volume event processing |
| Event Grid | An Azure or custom event is published | Reacting to changes such as a resource being created |
| Blob storage | A file is created or updated | Image processing, file imports |
| Cosmos DB and SQL | Data changes in a database | Reacting to updates and keeping systems in sync |
| Other connectors | Messages arrive from other brokers and systems | Integration with systems such as Kafka or RabbitMQ |
Examples of triggers with bindings
Photo thumbnail maker
The trigger is a new file in a storage container. An input binding provides the file content. An output binding writes the smaller image to another container.
Order confirmation
The trigger is a message in a service bus queue. The function reads the order, writes a record to a database through an output binding and sends a message to an email service.
Nightly report
A timer trigger fires at midnight. The function queries data, builds a summary and stores it for the morning.
Webhook receiver
An HTTP trigger receives a notification from an external service, validates it and places a message on a queue for further processing.
Queue Storage vs Service Bus
Queue storage is simple and cheap. Service Bus adds features such as topics, sessions, duplicate detection and dead-letter queues for enterprise messaging.
Event Grid vs Event Hubs
Event Grid delivers discrete notifications about things that happened. Event Hubs ingests large continuous streams of events for analysis.
A home has several kinds of bell: the doorbell, the alarm clock, the phone ringtone and the smoke alarm. Each tells you something different has happened and needs a different response. Triggers are the different bells for your code.
Using an HTTP trigger and a long synchronous chain of calls for work that should be asynchronous. Instead, accept the request quickly, place the work on a queue and let another function process it, so that the caller does not wait or time out.
6Hosting Plans and Cold Starts
The hosting plan is the most important choice you make for a function app.
| Plan | Scaling | Cold start | Networking | Best for |
|---|---|---|---|---|
| Flex Consumption | Event-driven, fast, scales to zero, with optional always-ready instances | Reduced, and can be avoided with always-ready instances | Supports virtual network integration | Most new serverless workloads, including those needing private networking |
| Consumption | Event-driven, scales to zero | Possible after idle periods | Limited networking features | Simple, spiky workloads. An older plan, so check the current recommendation and retirement notices |
| Premium | Event-driven with pre-warmed instances, always at least one running | Avoided through pre-warmed instances | Full virtual network features | Steady or latency-sensitive workloads with longer runs |
| Dedicated (App Service plan) | Manual or rule-based scaling on reserved machines | None when always on | Full features | Teams that already pay for spare App Service capacity |
| Container Apps hosting | Event-driven scaling on a container platform | Depends on minimum replicas | Container Apps networking | Teams that run containers and want Functions programming on the same platform |
flowchart TD
Q["Choose a hosting plan"] --> A{"Need private networking or fast scale with no idle cost?"}
A -->|"Yes"| FX["Flex Consumption"]
A -->|"Need constant warm instances and long runs"| PR["Premium"]
A -->|"Already have spare App Service capacity"| DD["Dedicated"]
A -->|"Standardised on containers"| CA["Container Apps hosting"]
Understanding cold starts
When no instance is running and an event arrives, a new instance must start, load the runtime and your code, and then process the event. This extra delay is the cold start. It may be a fraction of a second or several seconds depending on the language, the size of your code and its dependencies, and the plan.
Keep packages small
Large dependency sets and heavy start-up work lengthen cold starts. Remove unused libraries and do expensive set-up lazily.
Use always-ready or pre-warmed instances
Plans that offer them keep some instances ready, which removes cold starts for the first requests, at a cost.
Accept it where it does not matter
Background processing rarely cares about a one-second delay. Reserve warm instances for user-facing calls that need a quick response.
A tea stall that opens only when a customer walks up must light the stove first, so the first cup takes longer. A stall that keeps the stove warm serves immediately but burns fuel all day. Plans trade cold-start delay against idle cost in the same way.
Hosting plans evolve. Microsoft has announced changes to older plans, including retirement dates for some configurations, and recommends newer options for new work. Always read the current documentation before choosing a plan for a long-lived system.
7Scaling and Concurrency
Scaling happens at two levels: more instances, and more work at once on each instance.
Scaling out means adding instances. Concurrency means how many executions run at the same time on one instance. Both matter. If each function call is quick and light, one instance can run many in parallel. If each call is heavy, more instances are needed sooner.
Instance Scale-Out
The platform adds or removes instances based on the trigger source, with different rules for queues, streams and web requests, and within the limits of your plan.
Per-Instance Concurrency
Settings control how many messages or requests one instance processes at once. Too high can overload memory or downstream systems, and too low wastes capacity.
Maximum Instance Limits
You can cap the number of instances, to protect databases and external services from being overwhelmed.
Partition-Based Scale for Streams
For stream sources, scale is related to the number of partitions, since each partition is read by one instance at a time.
Know your downstream limits
Find out how many connections and requests your database, external APIs and other services can take.
Set maximum scale accordingly
Cap instances and concurrency so that a burst of events cannot flatten your dependencies.
Test with realistic bursts
Send many events at once and watch latency, errors and throttling in the downstream systems.
Tune and monitor
Adjust concurrency and limits, and set alerts on queue backlog and processing delay.
A bank can serve more customers by opening more counters, which is scaling out, or by training each clerk to handle two customers at once, which is concurrency. But if the vault has only one door, adding counters will not help, because the vault is the bottleneck.
Letting functions scale freely against a database that supports only a limited number of connections. The functions are happy, the database falls over, and the retries make things worse. Always set limits that respect the weakest link.
8Durable Functions: Workflows That Remember
Ordinary functions are short and stateless. Durable Functions add long-running, stateful workflows.
Some jobs take many steps over minutes, hours or days. An order might need payment, then stock reservation, then shipping, with waiting between steps and the possibility of failure at any point. Writing this with plain functions means building your own state tracking, retry logic and timers. Durable Functions is an extension that does this for you.
In Durable Functions, you write an orchestrator function that describes the workflow as ordinary code: do this, then wait for that, then do these three in parallel. The orchestrator calls activity functions, which perform the real work. The framework saves progress to storage after each step. If the instance stops, the workflow resumes from where it left off, by replaying the orchestrator’s history.
Orchestrator Function
Describes the workflow. Must be deterministic, which means it must make the same decisions when replayed.
Activity Function
Does one unit of real work, such as calling an API or writing to a database. May do anything.
Entity Function
Holds small pieces of state with operations, such as a counter or a shopping cart, accessed safely one operation at a time.
Client Function
Starts, queries and manages orchestrations, usually from an HTTP or queue trigger.
| Pattern | Idea | Example |
|---|---|---|
| Function chaining | Run steps in order, passing results along | Validate order, charge payment, create shipment |
| Fan-out and fan-in | Run many tasks in parallel, then combine results | Process thousands of files, then build one summary |
| Async HTTP API | Start a long job, return a status address, let clients check progress | Report generation that takes minutes |
| Monitor | Poll until a condition is met, with timers between checks | Wait until a remote job finishes |
| Human interaction | Wait for an approval, with a timeout | Manager approves an expense within three days |
flowchart TD
S["Start orchestration"] --> A1["Activity: validate order"]
A1 --> A2["Activity: charge payment"]
A2 --> P["Fan out"]
P --> B1["Activity: reserve item 1"]
P --> B2["Activity: reserve item 2"]
P --> B3["Activity: reserve item 3"]
B1 --> J["Fan in: combine results"]
B2 --> J
B3 --> J
J --> A3["Activity: create shipment"]
A project manager keeps a notebook of every step done and every step waiting. If the manager falls ill, a replacement reads the notebook and continues exactly where things stopped. The orchestrator is the manager, the activities are the workers and the saved history is the notebook.
Because the orchestrator is replayed, it must not use random numbers, current time, direct network calls or other non-repeatable behaviour inside its own code. Put such things in activities or use the framework’s special features, which are safe for replay.
Putting heavy work or network calls directly in the orchestrator. It breaks replay and makes results unpredictable. Keep orchestrators small and logical, and let activities do the actual work. Also keep the data passed between steps small.
9Reliability: Retries, Poison Messages and Idempotency
In a world of failures, good functions assume that things will be tried more than once.
Most event sources in Azure Functions deliver messages at least once. This means that a message is never lost, but it can occasionally be delivered more than once, for example after a crash or a timeout. If your function is not prepared for repeats, you may charge a customer twice or send duplicate emails.
At-Least-Once Delivery
Every message is delivered at least once. Duplicates are possible, so design for them.
Idempotency
An operation is idempotent if doing it twice has the same effect as doing it once. This is the key defence against duplicates.
Retries
When a function fails, many triggers retry automatically. You can also configure retry policies with delays that grow over time.
Poison Messages
A message that fails again and again is set aside, in a poison queue or dead-letter queue, so that it does not block the rest.
Make operations idempotent
Use unique identifiers for each message, check whether work was already done and use safe update patterns such as upserts.
Fail loudly for real errors
Let exceptions propagate so that the trigger can retry, instead of silently swallowing errors.
Configure retries sensibly
Use a limited number of retries with growing delays, so that temporary problems heal but permanent ones do not retry forever.
Handle poison messages
Monitor the poison or dead-letter queue, alert on new items and have a process to inspect, fix and replay them.
If a courier delivers a parcel twice by mistake, it is harmless when you simply sign for the same order number once and refuse the duplicate. Signing for every delivery without checking the order number leaves you with two parcels and a double bill.
Catching every exception and logging it without rethrowing. The trigger believes the work succeeded, the message is removed and the data is lost. Handle only errors you can truly fix, and let others fail so that they can be retried or sent to a poison queue.
10Configuration: Settings, Host Files and Secrets
Where you put settings decides how safe and flexible your function app is.
Application Settings
Named values stored with the function app in Azure and passed to your code as environment variables. They are different for each environment.
Host Configuration File
A file that sets behaviour of the runtime for all functions in the app, such as logging levels, retry defaults and concurrency settings.
Local Settings File
Used only on a developer’s computer, to hold settings and test connection strings. It must never be committed to source control.
Key Vault References
Application settings that point to secrets in Azure Key Vault. The platform fetches the secret using the app’s managed identity.
Identity-based connections
Many triggers and bindings can connect to Azure services using the function app’s managed identity instead of connection strings with keys. This removes secrets from configuration entirely.
Separate settings per environment
Keep development, test and production values separate, and build the code once so the same package runs everywhere.
Feature flags and central configuration
For many apps, a central configuration service lets you change behaviour without redeploying code.
A restaurant keeps the recipe the same in every branch, but the local manager changes the quantities, suppliers and opening hours for each city. The code is the recipe, and the settings are the local adjustments.
Committing the local settings file with real connection strings to a repository. Anyone with repository access can then reach your cloud resources. Exclude the file from source control and use Key Vault and managed identities in the cloud.
11Developing, Testing and Deploying
A good workflow lets you build on your own machine and release safely to the cloud.
Develop locally
Use Azure Functions Core Tools or an editor extension to run the Functions host on your computer, with local emulators for storage and queues, and debug with breakpoints.
Write tests
Keep business logic in ordinary classes or modules that can be tested without the runtime, and keep the function method thin.
Build a package in a pipeline
A pipeline compiles the code, runs tests and creates a deployment package.
Deploy using a package
Deploy the zipped package so that the app runs directly from it, which gives consistent, quick and repeatable releases.
Use slots or staged rollout where available
On plans that support deployment slots, release to a staging slot, test and swap into production with little downtime. Check which plans support slots today.
Verify and monitor
Check health, logs and key metrics after release, and roll back if needed.
Many Languages
Functions supports several languages, including C#, JavaScript and TypeScript, Python, Java and PowerShell, plus custom handlers for others. Check the current supported versions.
Isolated Worker Model for .NET
The recommended way to run .NET functions is in a separate worker process. The older in-process model has announced end of support, so use the isolated model for new work and plan migration for old apps.
Runtime Versions
Function apps run on a version of the Functions runtime. Keep apps on supported versions and upgrade before older ones are retired.
Infrastructure as Code
Define the function app, storage, identity and settings in templates, so that environments are repeatable.
A bakery tests a new recipe in a small trial batch in the back kitchen, then packs it in standard boxes and ships it to all shops on the same day. Local development, packaging and pipeline-based deployment give your code the same repeatable path to production.
Editing code directly in the portal for production functions. There is no review, no tests and no history, and the next deployment may overwrite the change. Treat production as read-only, and release only through pipelines.
12Security for Functions
Functions are small, but they are often public entry points to your systems, so protect them well.
Control who can call HTTP functions
HTTP functions can be anonymous, require a function key, or require an admin key. Keys are simple shared secrets and are not strong identity. For real user or application security, use platform authentication with an identity provider.
Use built-in authentication
The platform can require sign-in with Microsoft Entra ID or other providers before requests reach your code.
Use managed identities
Let the function app authenticate to other Azure services without secrets, and give it only the permissions it needs.
Protect secrets
Use Key Vault references, keep secrets out of code and settings files, and rotate any keys you must use.
Restrict the network
Use access restrictions, private endpoints and virtual network integration on plans that support them, so that only intended callers and services can connect.
Validate input and keep code safe
Treat all input as untrusted, validate it, keep dependencies up to date and follow safe coding practices.
Log and monitor
Record who called what, watch for unusual patterns and alert on failures and abuse.
Anonymous
No key is needed. Appropriate only when the function is protected in other ways, such as an authentication layer in front.
Function Key
Callers must send a key specific to the function or app. Simple protection for service-to-service calls and webhooks.
Admin Key
A powerful key that opens all functions and management endpoints. Guard it carefully.
A shop can leave its front door open, give regular customers a shared door code, or check each visitor’s identity card at the entrance. Keys are like the shared code: easy, but anyone who learns it can enter. Identity checks are much stronger for sensitive services.
Leaving an HTTP function anonymous because “it is just a small helper”. Public functions are found and abused quickly, and may reach databases and other resources through their identity. Authenticate every function that is exposed to the internet.
13Networking and Connectivity
Functions often need to reach private systems, and sometimes they must be reachable only privately.
Outbound: Virtual Network Integration
Lets the function app call resources inside your virtual network, such as private databases, and send outbound traffic through a firewall or NAT gateway.
Inbound: Private Endpoints and Restrictions
Lets only callers inside your network, or from approved addresses, reach the function app, removing its public exposure.
Hybrid Connections
A way to reach specific on-premises resources without opening a full network connection, on plans that support it.
Triggers from Private Sources
On plans with network support, triggers can read from queues and streams that are locked inside a virtual network.
Plan features matter
Not all plans offer all networking features. Flex Consumption, Premium and Dedicated plans provide the broadest options, while older consumption configurations are more limited. Check the plan’s current abilities before designing.
Fixed outbound addresses
If a partner must allow your function’s address, route outbound traffic through a NAT gateway or firewall so that a stable address is used.
Storage account networking
If you lock down the function app’s own storage account, make sure the app can still reach it through its network setup, or it will fail to start.
A courier company can have a door open to the public street, a pass that lets its riders enter a gated campus, and a private entrance only for staff. Outbound integration, inbound restriction and private endpoints are those passes and doors for your function.
Locking down the storage account, the queue and the database one by one and then wondering why the function stops working. Each step of the path needs both permission and a network route. Test connectivity after every network change.
14Monitoring and Troubleshooting
Because functions run unattended and in parallel, good telemetry is essential.
Azure Functions integrates with Application Insights, a monitoring service that collects information about every invocation, including duration, success or failure, dependency calls and exceptions. It also draws maps of how your functions and the services they use are connected, and traces a request across several functions.
Invocation Counts and Failures
How many times functions ran and how many failed. A sudden change often signals a problem.
Duration
How long executions take, including high percentiles. Rising duration may point to slow dependencies or cold starts.
Queue and Stream Backlog
The amount of waiting work. A growing backlog means functions cannot keep up.
Instance Count and Throttling
How many instances run and whether dependencies are rejecting calls.
Live Metrics
A near real-time view of requests, failures and servers, useful during releases and incidents.
Poison and Dead-Letter Queues
Counts of messages that could not be processed, which need human attention.
| Symptom | Likely cause | First check |
|---|---|---|
| Function never fires | Wrong trigger settings, disabled function, storage or connection problem | Host start-up logs, app settings, storage account access |
| Slow first request after quiet time | Cold start | Plan type, package size, always-ready or pre-warmed settings |
| Messages processed more than once | At-least-once delivery, timeouts, retries | Idempotency of the code, execution time against visibility timeout |
| Messages end up in poison queue | Repeated failures from bad data or bugs | Exception details in logs, message content |
| Backlog keeps growing | Not enough scale, slow dependencies or low concurrency | Instance count, maximum limits, downstream latency |
| Executions time out | Work exceeds the plan’s time limit | Plan timeout, split work or use Durable Functions |
A manager of many small delivery riders needs a map showing where each rider is, how long each delivery took and which parcels came back undelivered. Application Insights is that map and logbook for your functions.
Log meaningful, structured messages with identifiers that let you follow one order through several functions. For very busy apps, use sampling to control telemetry volume and cost, while keeping errors visible.
15Understanding and Controlling Cost
Functions can be extremely cheap, but a few details can surprise you.
| Plan | What you pay for | Cost character |
|---|---|---|
| Consumption | Number of executions and resource use measured in gigabyte-seconds, with a free monthly grant | Zero when idle, grows with use |
| Flex Consumption | Execution time and memory of running instances, plus optional charges for always-ready instances | Pay per use with a choice to pay for warm capacity |
| Premium | Processor and memory time of instances, including the minimum warm ones | Higher base cost, predictable performance |
| Dedicated | The App Service plan machines, whether busy or not | Fixed monthly cost |
Storage Account
The host’s own storage account has small charges for operations and capacity, which can grow with many functions or heavy trigger polling.
Application Insights
Telemetry is billed by volume. High-traffic functions with verbose logging can make this the biggest item.
Triggers and Bindings Services
Queues, event hubs, databases and networking have their own charges, which usually exceed the cost of the functions.
Data Transfer
Data leaving Azure or moving between regions is charged.
Right-size memory and duration
Make functions efficient. Faster code and smaller memory settings reduce the cost of each execution.
Batch where possible
Process messages in batches when the trigger supports it, which reduces the number of executions and overhead.
Avoid unnecessary polling and chatter
Do not call functions in tight loops or create infinite trigger cycles, such as a function writing to the same container that triggers it.
Control telemetry volume
Use sampling and sensible log levels, and avoid logging large payloads.
Pick the plan that matches the pattern
Consumption-style plans suit spiky traffic. For steady heavy traffic, a Premium or dedicated plan may be cheaper per execution. Compare using real numbers.
Set budgets and alerts
Watch spending, and alert on sudden jumps in executions that could mean a loop or an attack.
Paying a courier per parcel is cheap when parcels are few, but if a bug makes the shop send a million parcels to itself, the bill will be huge. Per-use pricing rewards efficiency and punishes loops, so watch the counters.
Creating a function that writes to the same storage container that triggers it. Each write triggers another run, creating an endless loop and a surprising bill. Use separate containers for input and output, and test with small data first.
16Azure Functions Compared with Other Options
Several Azure services run your logic, and each fits a different style of work.
| Service | Style | Best for | Less suited for |
|---|---|---|---|
| Azure Functions | Code-first, event-driven, small units | Glue code, event processing, APIs, scheduled tasks and workflows with Durable Functions | Very long uninterrupted processes, or software that needs full machine control |
| Logic Apps | Low-code visual workflows with many connectors | Integrating business systems with little code, approvals and enterprise connectors | Heavy custom computation |
| Azure Container Apps | Containers with autoscaling and jobs | Microservices, long-running workers, custom runtimes | Tiny pieces of code where containers are overkill |
| App Service | Always-on web app hosting | Full web applications with steady traffic | Event-driven scale to zero |
| Azure Kubernetes Service | Full container orchestration | Complex platforms and custom control | Simple tasks, since operations effort is high |
| Virtual Machines | Full control of the operating system | Legacy and special software | Short, event-driven snippets |
| Event Grid and Event Hubs | Event routing and ingestion, not compute | Delivering events to functions and other handlers | Running your code themselves |
flowchart TD
Q1{"Is the work event-driven and small?"} -->|"Yes"| Q2{"Prefer code or visual designer?"}
Q2 -->|"Code"| FN["Azure Functions"]
Q2 -->|"Visual and connectors"| LA["Logic Apps"]
Q1 -->|"No, long-running or containerised services"| Q3{"Need Kubernetes API?"}
Q3 -->|"No"| CA["Container Apps"]
Q3 -->|"Yes"| AKS["Kubernetes Service"]
Functions are like a helper you call for a specific errand. Logic Apps is a flowchart assistant who connects office systems by following a diagram. Container Apps is a small crew running a stall. App Service is a shop that is open all day. Pick the helper that fits the task.
Functions and Logic Apps together
Many solutions use Logic Apps for the workflow and connectors, and call Functions for pieces that need custom code.
Functions and Container Apps together
Functions can be hosted on Container Apps, letting teams use the Functions programming model with container tooling and networking.
If the job is small and driven by events, start with Functions. Move to a heavier service only when you hit a real limit, such as run time, custom runtime needs or complex multi-service orchestration.
17Design Patterns That Work Well
These approaches appear again and again in successful serverless systems.
Pattern: Queue-Based Load Leveling
A front function accepts work quickly and puts it on a queue. Worker functions process the queue at a steady, controlled pace, protecting back-end systems from sudden bursts.
Pattern: Event-Driven File Processing
A new file in storage triggers a function that validates, transforms and stores the result, with failures sent to a poison queue for review.
Pattern: Claim Check
Large payloads are stored in blob storage, and only a small reference is sent through queues and events. Functions fetch the payload when they need it.
Pattern: Fan-Out and Fan-In with Durable Functions
A large job is split into many small tasks processed in parallel, and their results are combined at the end.
Pattern: Saga for Long Business Processes
A durable orchestration coordinates steps across services and runs compensating actions, such as refunds, if a later step fails.
Pattern: Serverless API Back End
HTTP functions behind an API gateway handle requests, using managed identities to read and write data, with authentication at the gateway.
Pattern: Scheduled Housekeeping
Timer functions run clean-up, reports and synchronisation at fixed times, costing little because they run briefly.
flowchart LR
U["Client"] --> API["HTTP Function: accept request"]
API --> Q["Queue"]
Q --> W["Worker Function: process with limits"]
W --> DB["Database"]
W --> PQ["Poison Queue for failures"]
W --> N["Notification Function"]
18Real-World Examples
Azure Functions quietly powers a wide range of everyday systems.
An e-commerce order flow
When an order is placed, a message triggers functions that validate it, reserve stock, call the payment service, email the customer and update analytics. During sales, the number of instances grows automatically and then shrinks again.
A media company processing uploads
Uploaded videos and images trigger functions that create thumbnails, check content and extract metadata. A durable orchestration handles larger, multi-step encoding jobs and waits for completion.
Internet of Things data handling
Devices send readings to an event stream. Functions read the stream, filter and enrich readings, store them and raise alerts when thresholds are crossed.
A bank’s scheduled reports
Timer functions assemble daily statements and compliance reports, write them to secure storage and notify teams. Retry policies and alerts handle failures.
Integrating software-as-a-service tools
Webhook functions receive notifications from external services, check signatures and place events on queues, connecting separate systems without a permanent server.
AI document pipelines
New documents trigger functions that extract text, call AI services, store results and update a search index, scaling with the volume of uploads.
Advantages
- No servers to manage, with automatic scaling
- Pay-per-use pricing and a free monthly grant on consumption-style plans
- Rich triggers and bindings for many services
- Durable Functions for reliable long workflows
- Quick development and many supported languages
Disadvantages / Trade-offs
- Cold starts on plans that scale to zero
- Execution time limits on some plans
- At-least-once delivery requires idempotent design
- Many small functions can be harder to understand and debug as a whole system
- Plans and runtime versions change, so documentation needs regular rechecking
19Anti-Patterns to Avoid
These habits regularly cause duplicate work, outages and surprise bills.
Problem
Functions assume that each message arrives exactly once, and perform non-repeatable actions such as charging cards or sending emails without checks.
Why It’s Harmful
Duplicates occur after retries and timeouts. Customers are charged twice, receive repeated messages and data becomes inconsistent.
Correct Approach
Design for at-least-once delivery. Use unique identifiers, check before acting, use upserts and make every operation safe to repeat.
Problem
A single function tries to run a long, multi-step process, or functions call each other in long synchronous chains over HTTP.
Why It’s Harmful
Time limits are reached, failures in the middle leave work half done, and a slow step blocks the whole chain and its callers.
Correct Approach
Use queues between steps, or Durable Functions for workflows, so that each step is small, retryable and its state is saved.
Problem
Functions scale without limits against databases and external services, and keep important state in memory or on local disk.
Why It’s Harmful
Bursts overwhelm dependencies, and instances disappear at any time taking their in-memory state with them.
Correct Approach
Cap instances and concurrency to match dependency limits, and keep all state in managed stores such as databases, caches and storage.
Problem
HTTP functions are left anonymous, secrets sit in settings or source control, and production code is edited in the portal.
Why It’s Harmful
Public endpoints are abused, secrets leak, and untracked changes make the system unpredictable and hard to restore.
Correct Approach
Authenticate every exposed function, use managed identities and Key Vault, and deploy only through reviewed pipelines.
Problem
A function writes its output to the same place that triggers it, or errors are caught and ignored so that failures disappear silently.
Why It’s Harmful
Endless trigger loops create huge bills, and swallowed errors cause lost data with no alert.
Correct Approach
Use separate input and output locations, let genuine failures propagate for retry and poison handling, and alert on failures and unusual execution counts.
20Best Practices and a Starter Checklist
Walk through these steps whenever you plan a new function app.
Confirm that Functions fits the job
Check that the work is event-driven and short enough, or can be split with queues or Durable Functions.
Choose the hosting plan on purpose
Match scaling, networking, cold start and cost needs to a plan, and check the current plan status and retirement notices.
Keep functions small and focused
Do one job per function, keep business logic in testable code and group functions by shared scaling needs.
Design for retries and duplicates
Make operations idempotent, configure retries, handle poison messages and avoid swallowing exceptions.
Respect downstream limits
Set maximum instances and concurrency, use queues to level load, and test with bursts.
Secure everything exposed
Authenticate HTTP functions, use managed identities and Key Vault, restrict the network and keep dependencies updated.
Deploy through pipelines
Use packages, infrastructure as code, staged releases and rollbacks, and keep environments consistent.
Monitor and control cost
Use Application Insights with sampling, alert on failures, backlog and unusual execution counts, set budgets and review the plan against real usage.
Assuming exactly-once delivery, building long chains of synchronous calls, scaling without limits, keeping state in memory, leaving HTTP functions anonymous, editing production in the portal, creating trigger loops, ignoring poison queues and not checking plan and runtime retirement notices.
21Frequently Asked Questions
It means that you do not manage the servers. You provide code, and Azure provisions, scales and maintains the machines that run it. There are still servers underneath, but you do not see or operate them.
A trigger is the event that starts a function, and every function has exactly one. A binding is an optional, declared connection to data, such as reading a record or writing a message, either as input or output.
A cold start is the extra delay when a new instance must start before running your function, usually after a quiet period. You can reduce it by keeping packages small, avoiding heavy start-up work and using plans or settings that keep instances warm, such as always-ready or pre-warmed instances.
For most new serverless workloads, Flex Consumption is a strong default because it scales quickly and supports private networking. Choose Premium for steady, latency-sensitive or long-running work, Dedicated if you already have spare App Service capacity, and check the current documentation for plan status and limits.
They are used for reliable, long-running workflows with many steps, waiting, parallel work and human approvals. The framework saves progress, so that a workflow can continue after failures or restarts.
Most triggers use at-least-once delivery, so duplicates can happen after retries, timeouts or crashes. Make your function idempotent, so that repeating the same message does no harm.
Do not leave it anonymous if it is exposed to the internet. Use platform authentication with an identity provider where possible, use function keys only for simple service-to-service cases, and restrict the network, use managed identities and keep secrets in Key Vault.
Cap the maximum number of instances, limit concurrency per instance and put a queue between the caller and the worker functions, so that work is processed at a controlled pace. Add retries with delays in your code.
Make functions efficient, batch work, avoid loops and unnecessary polling, control telemetry volume with sampling, choose the plan that matches your traffic pattern and set budgets and alerts for unexpected spikes.
Use Functions for code-first, event-driven tasks. Use Logic Apps when a visual workflow with many connectors fits better. Use Container Apps for containerised services, long-running workers or custom runtimes. Many solutions combine them.
22Summary and Key Takeaways
Azure Functions runs small pieces of code in response to events, without any servers for you to manage. A function has one trigger and optional bindings, and functions are grouped in function apps that scale together according to a hosting plan. The scale controller adds and removes instances as events arrive, so you pay for use rather than idle time. Durable Functions add reliable long-running workflows, while good design for retries, idempotency, poison messages and downstream limits keeps systems safe. With managed identities, Key Vault, careful networking, pipeline-based deployment, strong monitoring and attention to cost, Azure Functions lets small teams build responsive, scalable systems quickly.
Key Takeaways
- Event-driven and serverless — code runs only when a trigger fires, scaling automatically and billing by use, with no servers for you to manage.
- Triggers, bindings and apps — each function has one trigger and optional bindings, and functions in a function app share scaling, settings and plan.
- The plan shapes everything — choose among Flex Consumption, Consumption, Premium, Dedicated and Container Apps hosting for scaling, networking, cold start and cost, and check retirement notices.
- Design for failure — expect at-least-once delivery, make operations idempotent, configure retries, handle poison messages and let real errors fail.
- Protect your dependencies — cap instances and concurrency, level load with queues and test with realistic bursts.
- Use Durable Functions for workflows — orchestrators, activities and entities give reliable, stateful, long-running processes, as long as orchestrators stay deterministic.
- Secure, observe and control cost — authenticate exposed functions, use managed identities and Key Vault, monitor with Application Insights, deploy through pipelines and watch for loops and telemetry growth.