AWS Lambda Event Triggers Explained: S3, SQS, SNS, EventBridge and More
Lambda runs your code in response to events: an HTTP request, a file uploaded to S3, a message in a queue, or a scheduled timer. You write the function; AWS handles when and how often to run it. Nothing runs, nothing costs money, until an event fires.
This page explains how that model works in practice: which AWS services can trigger Lambda, how Lambda handles each trigger differently, what happens when something fails, and when this approach is the right choice versus when a different compute model fits better.
What event-driven compute actually means
In a traditional architecture, a web server process runs continuously. It sits idle between requests and handles each one as it arrives. You pay for the server whether it is busy or not.
Lambda works differently. Nothing runs until an event triggers it. When an event fires, AWS creates an execution environment, runs your handler function, and terminates it once the function returns. Between events, nothing is running and nothing is billed.
Analogy: the motion-sensor light
A motion-sensor light is off all day. It consumes almost no power. The moment someone walks into the room, it switches on, does its job, and turns off again when the room is empty. You pay for the seconds it was on, not the hours it sat ready. A traditional server is like leaving the light on all day just in case someone might walk in.
This model works well for discrete, bounded workloads with unpredictable arrival rates. It becomes a problem for workloads that need persistent state, sub-100ms latency on every single request, or runtimes longer than 15 minutes. The AWS Lambda overview covers how Lambda works end-to-end, including cold starts, execution environments, and concurrency.
How Lambda event invocation works
Every Lambda invocation follows the same basic flow:
- An event happens: a user uploads a file, an API receives a POST, a queue receives a message, a schedule fires.
- AWS packages the event: the triggering service constructs a structured JSON payload describing what happened and passes it to Lambda.
- Lambda invokes your function: AWS routes the event to a free execution environment, or creates a new one (cold start) if none is available.
- Your handler processes the event: your function receives the event object and a context object, does its work, and returns a result.
- Lambda handles the outcome: for synchronous triggers, the result goes back to the caller. For asynchronous triggers, success means done; failure means retry, then dead letter queue. For event source mappings, successful processing deletes the message; failure holds the batch for retry.
Steps 1 to 3 are handled by AWS. You write step 4. Understanding step 5 is what most people underestimate; the error handling behaviour differs substantially depending on how your function was triggered.
If you have not deployed a Lambda function yet, Deploying Your First Lambda Function walks through the full setup with the AWS CLI.
Common Lambda trigger sources
API Gateway and Lambda Function URLs
API Gateway (HTTP API or REST API) triggers Lambda synchronously in response to HTTP requests. The function receives the full request as an event object and returns an HTTP response. This is the most common way to build serverless APIs and webhooks.
Lambda Function URLs give a function its own HTTPS endpoint without routing through API Gateway, which is simpler and cheaper for single-function endpoints or webhook receivers that do not need request transformation, auth policies, or rate limiting at the gateway level.
S3
S3 notifies Lambda when objects are created, updated, or deleted. The invocation is asynchronous: S3 fires and does not wait. Lambda receives the bucket name and object key in the event payload.
Real uses: resize images when photos are uploaded, scan new files for malware, trigger a data processing pipeline when a CSV arrives, archive files on deletion.
One thing to configure beyond the function itself: you also need to add a notification configuration to the S3 bucket. Granting Lambda permission for S3 is not enough. Both the permission and the bucket notification are required.
SQS
Lambda polls an SQS queue and processes messages in batches. When the function succeeds, Lambda deletes the processed messages. When it fails, messages return to the queue for retry. This is an event source mapping: Lambda manages the polling internally, rather than SQS pushing to Lambda.
SQS is the right choice when you want durable buffering between the event producer and Lambda. It absorbs traffic spikes, decouples services, and gives you natural retry behaviour at the queue layer. SNS vs SQS gives a clear comparison of when each service fits.
def handler(event, context):
for record in event['Records']:
body = record['body']
print(f"Processing: {body}")
# Return without error -> Lambda deletes the messages
# Raise an exception -> messages return to the queueSNS
SNS topics push notifications directly to Lambda asynchronously. SNS sends and does not wait. This is useful for fan-out patterns: one SNS message can trigger multiple Lambda functions simultaneously, or reach SQS queues and Lambda functions at the same time.
The trade-off: SNS itself has no retry queue. If your Lambda function is throttled or fails to process an SNS notification, you need a DLQ on the Lambda function to catch the lost event.
EventBridge
Amazon EventBridge routes events from AWS services and custom applications to Lambda based on rules you define. Two common patterns:
- Scheduled rules: run a Lambda function on a cron schedule for nightly cleanup, hourly report generation, or daily data exports.
- Event pattern rules: trigger Lambda when an AWS service emits a specific event, such as an EC2 instance changing state, a CodePipeline stage failing, or a custom application publishing a business event.
EventBridge is the routing layer. It does not run code itself; it receives events and decides which targets to invoke.
DynamoDB Streams
DynamoDB Streams captures a time-ordered record of every change to a table: inserts, updates, and deletes. Lambda processes these change records in near real-time, receiving batches of INSERT, MODIFY, and REMOVE records.
Real uses: replicate changes to a search index, send a notification when a record is updated, maintain an audit log, invalidate a cache when source data changes.
Kinesis Data Streams
Lambda polls Kinesis shards and processes records in order within each shard. Multiple shards run concurrently. Use Kinesis when you need high-throughput, ordered streaming data: application logs, clickstream analysis, IoT sensor readings, or real-time metrics pipelines.
Cognito
Lambda can hook into the Cognito authentication flow at several trigger points: before sign-in, after confirmation, to customise access tokens, to run pre-signup validation, or to migrate users from a legacy identity system. These triggers are synchronous. Cognito waits for Lambda to respond before proceeding.
Synchronous, asynchronous, and event source mappings
Lambda has three distinct invocation modes. The mode determines who waits for a result, who retries on failure, and whether batching applies.
| Mode | Caller waits? | Lambda retries on failure? | Batching? | Example triggers |
|---|---|---|---|---|
| Synchronous | Yes | No (caller must retry) | No | API Gateway, ALB, Function URLs, Cognito |
| Asynchronous | No | Yes (up to 2 retries, then DLQ) | No | S3, SNS, EventBridge |
| Event source mapping | No | Yes (until success or expiry) | Yes | SQS, Kinesis, DynamoDB Streams |
Why the mode matters operationally
Synchronous: if your function fails, the caller gets an error immediately. For an API, that means returning a 500 to the user. There is no automatic retry. Your API client or the user must decide what to do. Error handling lives in the caller.
Asynchronous: the caller is gone by the time your function runs. If it fails, Lambda retries quietly. If retries are exhausted, the event is silently dropped unless you have a dead letter queue configured. Without a DLQ, you will have no idea events were lost unless you set up monitoring.
Event source mappings: Lambda holds the batch until it processes successfully or the message expires. For SQS, an unresolved failure keeps the message in the queue. For Kinesis and DynamoDB Streams, a stuck shard blocks all records behind it. Lambda Scaling and Concurrency Explained covers how these polling models interact with Lambda’s concurrency limits.
When Lambda event-driven compute is the right fit
Lambda handles event-driven workloads well in these scenarios:
- File processing: something arrives (a photo, a CSV, a log file) and needs work done on it. The trigger fires, the function runs, done. This is the classic Lambda use case.
- Queue consumers: messages arrive at variable rates and you want Lambda to process them without managing workers. SQS and Lambda together handle queue depth automatically.
- Scheduled jobs: nightly cleanup, hourly reports, daily exports. An EventBridge cron rule and Lambda together replace cron servers entirely.
- Event reactions: respond to AWS service events by running a function whenever a new IAM user is created, an EC2 instance starts, or an RDS snapshot completes.
- Lightweight APIs and webhooks: HTTP endpoints that receive a request, do something small (validate, transform, persist), and return a result. Fits well under API Gateway or a Function URL.
- Fan-out processing: one event triggers multiple downstream actions simultaneously. SNS or EventBridge routes to several Lambda functions in parallel.
For a broader look at how these patterns fit together in production, see Event-Driven Architectures in AWS.
When Lambda is a poor fit
Lambda has real constraints. These are the scenarios where a different compute model is the better choice:
- Long-running workloads: Lambda has a 15-minute maximum runtime. Video encoding, large batch jobs, and processes that take hours belong on EC2 or ECS. Lambda vs EC2 breaks down the trade-offs with real examples.
- Heavy stateful processing: Lambda execution environments do not share memory. If your function needs to coordinate state across thousands of concurrent invocations, a container with shared storage or a persistent process is simpler to reason about.
- Strict sub-100ms latency on every request: cold starts add variable latency. Provisioned concurrency eliminates cold starts but at extra cost. If you need consistently fast responses under unpredictable load, ECS Fargate or EC2 with a warm pool may be more predictable. Lambda vs ECS covers this trade-off directly.
- Multi-step orchestration with conditional logic: chaining Lambda functions by having one invoke the next becomes hard to manage fast. Once you have branching, retries, timeouts, and visibility across three or more steps, AWS Step Functions is the right tool.
- Sustained high-throughput workloads: at high constant throughput, a reserved EC2 instance is significantly cheaper than Lambda billed per-invocation. Lambda pricing compounds at scale.
The Choosing Between EC2, Lambda, and Containers guide and the three-way compute decision framework help work through these trade-offs by workload type.
Lambda, EventBridge, SNS, SQS, and Step Functions: what each one does
These services are often discussed together but serve different roles. EventBridge is not Lambda. SNS and SQS are not interchangeable. Understanding what each service is responsible for makes the patterns much easier to reason about.
| Service | What it does | Runs code? | When to use it |
|---|---|---|---|
| Lambda | Executes your function code | Yes | The compute layer: any time work needs to be done |
| EventBridge | Routes events to targets based on rules | No | Scheduling, AWS service event reactions, custom event routing |
| SNS | Push pub/sub messaging; fans out to many subscribers | No | Notify multiple targets simultaneously from one event |
| SQS | Durable message queue; one consumer per message | No | Buffering, decoupling, controlled throughput, retry queuing |
| Step Functions | Orchestrates workflows across services | No (coordinates others) | Multi-step flows with branching, retries, human approval, timeouts |
EventBridge or SNS routes an event to an SQS queue, and Lambda consumes the queue. This gives you routing, fan-out, durable buffering, and controlled execution in one pipeline. Event-Driven Systems in AWS covers how these pieces fit together with real architecture examples.
Event payloads and handler expectations
Each trigger sends a different JSON structure to your function. Your handler code needs to know the shape for the trigger it is receiving. The three most common ones look like this:
API Gateway HTTP API v2 event (simplified):
{
"version": "2.0",
"routeKey": "POST /orders",
"rawPath": "/orders",
"headers": { "content-type": "application/json" },
"requestContext": {
"http": { "method": "POST", "path": "/orders", "sourceIp": "1.2.3.4" }
},
"body": "{\"item\": \"widget\", \"quantity\": 5}",
"isBase64Encoded": false
}S3 event:
{
"Records": [{
"eventSource": "aws:s3",
"eventName": "ObjectCreated:Put",
"s3": {
"bucket": {"name": "my-uploads-bucket"},
"object": {"key": "uploads/photo.jpg", "size": 102400}
}
}]
}SQS event:
{
"Records": [{
"messageId": "abc-123",
"body": "{\"orderId\": \"12345\", \"action\": \"process\"}",
"attributes": {"ApproximateReceiveCount": "1"},
"eventSource": "aws:sqs",
"eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:my-queue"
}]
}S3 and SQS both wrap records in a Records array. API Gateway does not. Check the event schema for each trigger type; the AWS documentation for each service lists the exact payload structure.
Failure handling and reliability
Synchronous failures
The error is returned to the caller. Lambda does not retry. The caller (whether API Gateway, an ALB, or your own code invoking Lambda directly) must decide how to respond. For API-driven flows this typically means returning an appropriate HTTP error code to the client.
Asynchronous failures
Lambda retries the invocation twice (three total attempts) with increasing delays between attempts. After all retries fail, the event is sent to the dead letter queue (SQS or SNS) if one is configured, or silently dropped.
Without a dead letter queue, failed async events vanish with no trace. There is no error log entry for the lost event in Lambda itself. Always configure a DLQ for Lambda functions that process async events where losing data is unacceptable. Monitoring AWS Lambda Functions covers the CloudWatch metrics and alarms that surface async failures before they become a problem.
Event source mapping failures
For SQS, a failed batch returns to the queue and will be retried when the visibility timeout expires. For Kinesis and DynamoDB Streams, an unresolved failure blocks the affected shard. No new records from that shard are processed until the failure is resolved or the records expire.
Configure a DLQ on the event source mapping itself, not on the Lambda function’s async config. The two DLQ mechanisms are separate and serve different failure paths. Configuring only one of them will not protect you in the other scenario.
Idempotency
Lambda provides at-least-once delivery for async and event source mapping invocations, not exactly-once. The same event can be delivered more than once, especially during retries. Design your handlers to be idempotent: if the same message is processed twice with the same ID, the outcome should be identical to processing it once.
A practical approach: include a unique identifier with each event (order ID, message ID, correlation ID) and check whether the work has already been done before acting. A DynamoDB conditional write or a cache-layer deduplication check are common patterns.
SQS: batch size and partial batch failures
Lambda processes SQS messages in batches. By default, if any message in the batch causes an exception, the entire batch returns to the queue, including messages that were processed successfully. Those successful messages will be processed again.
Without partial failure reporting, one poisoned message causes every message in the batch to retry indefinitely. This drives up invocation counts, creates duplicate processing, and can grind your queue consumer to a halt. Always enable ReportBatchItemFailures for SQS event source mappings.
Enable ReportBatchItemFailures to return only the failed message IDs. Lambda deletes the successful ones and retries only the ones that actually failed:
def handler(event, context):
failed_message_ids = []
for record in event['Records']:
try:
process_message(record['body'])
except Exception as e:
print(f"Failed: {record['messageId']}: {e}")
failed_message_ids.append({'itemIdentifier': record['messageId']})
return {'batchItemFailures': failed_message_ids}aws lambda update-event-source-mapping \
--uuid <mapping-uuid> \
--function-response-types ReportBatchItemFailuresLambda Cost Optimisation covers how batching and retry configuration affect Lambda spend at scale.
Common mistakes
- No dead letter queue for async functions. Without a DLQ, failed async events are silently discarded. You will never know they were lost. Configure a DLQ for every Lambda function that processes async events where data loss is unacceptable.
- Non-idempotent handlers. Async and event source mapping invocations can deliver the same event more than once. If your function writes to a database and Lambda retries, you get duplicate writes. Design handlers so that processing the same event twice produces the same result as processing it once.
- Not using ReportBatchItemFailures with SQS. Without partial failure reporting, one bad message causes the whole batch to retry. Every message in the batch gets processed again, including the ones that already succeeded.
- Missing S3 bucket notification configuration. Granting Lambda permission to be invoked by S3 is not enough. You also need to configure the bucket’s event notifications to send events to the function. Both steps are required.
- Using Lambda for workloads that belong on ECS or EC2. Lambda has a 15-minute timeout and no persistent memory between invocations. If you are regularly running against those limits, a container on ECS or a VM on EC2 is the better starting point. Read about the AWS Lambda Security Model to understand the security boundaries that apply when Lambda does fit.
- Chaining Lambda functions instead of using Step Functions. Having one Lambda function invoke the next works for two steps. With branching, retries, timeouts, and visibility across three or more steps, move to AWS Step Functions. The operational overhead of hand-rolled orchestration compounds quickly.
Summary
- Lambda runs code only when an event fires: no idle cost, no persistent process between invocations.
- Common trigger sources: API Gateway (synchronous HTTP), S3 (async file events), SQS (polled queue), SNS (async push), EventBridge (scheduled and event rules), DynamoDB Streams and Kinesis (ordered streams).
- Synchronous invocations return the result to the caller; Lambda does not retry on failure.
- Asynchronous invocations retry up to twice before routing to a dead letter queue (if configured) or dropping the event silently.
- Event source mappings poll SQS, Kinesis, and DynamoDB Streams and hold failed batches until resolved or expired.
- Configure a DLQ for async functions; use ReportBatchItemFailures for SQS batches; design handlers to be idempotent.
- Lambda, EventBridge, SNS, SQS, and Step Functions are complementary. Lambda is the compute layer; the others route, queue, or orchestrate.
Frequently asked questions
What is event-driven compute?
Event-driven compute means your code runs in response to events (an HTTP request, a file upload, a message in a queue, a scheduled timer) rather than running continuously. Lambda is the primary event-driven compute service in AWS. You define the trigger; Lambda runs your function when the event occurs and stops immediately after.
What is the difference between synchronous and asynchronous Lambda invocation?
Synchronous invocations wait for the function to return a result before responding to the caller (API Gateway, Lambda Function URLs). Asynchronous invocations are fire-and-forget: the caller gets a 202 immediately and Lambda processes the event in the background. For async invocations Lambda retries failures twice before routing to a dead letter queue if one is configured.
Does EventBridge run code?
No. EventBridge routes events. It receives events from AWS services or custom applications and forwards them to targets like Lambda, SQS, or Step Functions based on rules you define. Lambda does the actual work. EventBridge is the router; Lambda is the executor.
When should I use SQS with Lambda instead of a direct trigger?
Use SQS when you want durable buffering, controlled throughput, and automatic retries. SQS absorbs traffic spikes and lets Lambda process messages at its own pace. Direct invocations work for synchronous flows where the caller needs an immediate response, but they offer no built-in buffering or retry queue.
What happens when a Lambda invocation fails?
It depends on the invocation type. Synchronous failures return an error to the caller. Lambda does not retry. Asynchronous failures trigger up to 2 automatic retries; after that the event goes to a dead letter queue if configured, or is silently dropped. Event source mapping failures (SQS, Kinesis, DynamoDB Streams) hold the batch until the failure is resolved or the message expires.