Azure Functions triggers and bindings
In Azure Functions, a trigger is what starts a function and a binding is a declarative connection to another service, either as input (data passed in) or output (data written out). The decision rule for exams: every function has exactly one trigger and any number of optional input and output bindings; pick the trigger by what should cause the code to run, and use an output binding when the only job is to write the result somewhere.
This page is a cheat sheet. For the hosting side, see App Service plans, because the Dedicated option runs functions in one, and choosing an Azure compute service for when Functions is the right service at all.
The three roles
Microsoft Learn describes a trigger as a special kind of input binding: it both invokes the function and passes data in (triggers and bindings concepts). Bindings are optional, and you can always skip them and use an Azure SDK client in your code instead; bindings only save you that client code. Connection details are not written in code: the connection property names an app setting (or a group of settings sharing a prefix for identity-based connections), and a Key Vault reference in that setting keeps the string out of the app configuration (Azure Key Vault).
Syntax: Python v2 programming model
In the Python v2 model, triggers and bindings are decorators. In the older v1 model and in other languages that use function.json, the same information is a JSON file with a direction of in or out. The sketch below takes an HTTP request, writes it to a storage queue through an output binding, and processes it in a second function with a queue trigger.
import logging
import azure.functions as func
app = func.FunctionApp(http_auth_level=func.AuthLevel.FUNCTION)
@app.route(route="orders", methods=["POST"])
@app.queue_output(arg_name="msg", queue_name="orders", connection="AzureWebJobsStorage")
def submit_order(req: func.HttpRequest, msg: func.Out[str]) -> func.HttpResponse:
msg.set(req.get_body().decode("utf-8"))
return func.HttpResponse("queued", status_code=202)
@app.queue_trigger(arg_name="item", queue_name="orders", connection="AzureWebJobsStorage")
def process_order(item: func.QueueMessage) -> None:
logging.info("order %s, attempt %s", item.get_body().decode("utf-8"), item.dequeue_count)
submit_order has one trigger (HTTP) and one output binding (queue). process_order has one trigger (queue) and no bindings. Putting a second trigger decorator on either is not allowed.
Which bindings exist
From the supported bindings table on Learn (the table also lists others, such as Kafka and RabbitMQ):
| Service | Trigger | Input | Output |
|---|---|---|---|
| HTTP and webhooks | yes | yes | |
| Timer | yes | ||
| Queue Storage | yes | yes | |
| Service Bus | yes | yes | |
| Event Grid | yes | yes | |
| Event Hubs | yes | yes | |
| Blob Storage | yes | yes | yes |
| Azure Cosmos DB | yes | yes | yes |
| Azure SQL | yes | yes | yes |
| Table Storage | yes | yes | |
| SendGrid | yes |
Learn also marks two things to remember: all bindings except HTTP and timer need their extension registered, and the Kafka and RabbitMQ triggers are not supported in the legacy Consumption plan.
Settings that decide answers
HTTP trigger. The authorization level is anonymous (no key), function (a function-specific key) or admin (the master key). When no level is set it defaults to function for Python, C# and Java. For Node.js, the v4 model defaults to anonymous. The key goes in the code query parameter or an x-functions-key header. An HTTP-triggered function must respond within 230 seconds regardless of the function timeout, because of the load balancer idle limit (HTTP trigger). For longer work, return immediately and hand over to a queue, as in the sketch above.
Timer trigger. The schedule is an NCRONTAB expression with a sixth field for seconds at the start: {second} {minute} {hour} {day} {month} {day-of-week}. 0 */5 * * * * runs every five minutes and 0 30 9 * * 1-5 runs at 09:30 on weekdays. The time zone is UTC unless you set WEBSITE_TIME_ZONE. When the app scales out, only one instance of a timer function runs, and a timer does not retry after a failure; it waits for the next occurrence. A TimeSpan schedule works only on an App Service plan (timer trigger).
Queue Storage trigger. The runtime tries a failing message up to five times in total. After that it moves the message to a queue named <originalqueuename>-poison. The default batch size is 16 and a new batch is fetched when 8 remain, so up to 24 messages per function per VM run concurrently (queue trigger). Compare Service Bus, which has its own dead-letter queue, covered in the AI-200 connect guide.
Azure SQL trigger. It uses SQL change tracking, so change tracking must be enabled on both the database and the table. It polls (default every 1,000 ms) and the database principal needs more than db_datareader and db_datawriter (SQL trigger).
Plans. Learn lists Flex Consumption, Premium, Dedicated, Container Apps and the legacy Consumption plan; for new serverless apps it points to Flex Consumption, and Linux Consumption is retired from September 30, 2028 (hosting options). The default execution timeout is 30 minutes on Flex Consumption, Premium and Dedicated, and 5 minutes (maximum 10) on the legacy Consumption plan. Support for the C# in-process model ends on November 10, 2026, so isolated worker is the model to know.
Which exams test this
| Exam | How it appears | Where on this site |
|---|---|---|
| AI-200 | “Connect to and consume Azure services” (20-25%), group “Develop and implement Azure Functions”: build serverless APIs including triggers and bindings, configure and deploy function apps | Connect to Azure services explained |
| DP-800 | “Secure, optimize, and deploy database solutions” (35-40%), “Integrate SQL solutions with Azure services”: handle changes with change event streaming, CDC, Change Tracking, Azure Functions with SQL trigger binding or Logic Apps. Also “Implement AI capabilities” (25-30%): choose an embedding maintenance method. Outline applies from October 19, 2026. | AI capabilities explained |
| SC-500 | “Secure compute” (20-25%): security controls for Azure Functions, including authentication and network access | Secure compute explained |
| AZ-305 | Minor: “Design infrastructure solutions” (30-35%) includes recommending a serverless-based solution | Infrastructure explained |
| AZ-900 | Minor: compare compute types including functions; serverless concept | Architecture and services explained |
Triggers and bindings are named explicitly only in AI-200 and, for the SQL trigger, DP-800. The other rows test Functions as a service.
How exam questions are built around triggers and bindings
- One trigger. An option that gives a function “a queue trigger and a timer trigger” is wrong. Two causes means two functions.
- Trigger or binding. “Start when a blob arrives” is a trigger. “Also read a row from Cosmos DB” is an input binding. “Write a result to a queue without client code” is an output binding.
- Polling or push. Timer and queue triggers poll or schedule; Event Grid pushes. “React immediately to an event published by a service” points to Event Grid.
- Failure behaviour. Queue messages end in a poison queue after five tries; timers do not retry.
- Hidden key requirement. “Callable from a browser without a key” means
anonymous. “Only callers with the app’s master key” meansadmin. - Credential-free connections. The answer that swaps a connection string for an identity-based connection or Key Vault reference usually wins.
- Long HTTP work. Anything over 230 seconds needs an asynchronous pattern, not a bigger timeout.
Practice questions
Question 1. A single function must run whenever a message arrives on a Service Bus queue and also once every night at 02:00 UTC to rebuild a cache. How should you implement this?
- A. One function with a Service Bus trigger and a timer trigger
- B. Two functions in one function app, one with a Service Bus trigger and one with a timer trigger
- C. One function with a Service Bus trigger and a Service Bus input binding
- D. One function with an HTTP trigger and a timer output binding
Show answer
Answer: B
A function must have exactly one trigger, so two different causes need two functions, which can live in the same function app. A function cannot have both a Service Bus trigger and a timer trigger. A Service Bus input binding is not a trigger. An HTTP trigger with a timer output binding does not schedule anything, because the timer is a trigger only and has no output binding.
Question 2. A function with a Storage queue trigger throws an exception every time it processes one malformed message. With default settings, what happens to that message?
- A. It is deleted after the first failed attempt
- B. It is retried indefinitely until the function succeeds
- C. It is moved to the originalqueuename-poison queue after five attempts
- D. It is moved to a Service Bus dead-letter queue after five attempts
Show answer
Answer: C
The queue trigger retries a failing message up to five times in total, including the first attempt, and then moves it to a queue named after the original queue with the suffix -poison. It is not deleted after the first failure, it is not retried forever, and Storage queues have no Service Bus dead-letter queue.
Go deeper
- Triggers and bindings in Azure Functions (concepts, supported bindings table)
- Azure Functions HTTP trigger (authorization levels, keys)
- Timer trigger for Azure Functions (NCRONTAB, time zones)
- Azure Functions hosting options
- Related guides: Azure load balancing options, CI/CD explained, the AI-200 exam guide, How to study for certification exams