As you may know, I’m a big fan of serverless in AWS. The primary compute component of serverless in AWS is AWS Lambda, so as you might imagine, I use it a lot. When using Lambda, I try to follow best practices for retries and dead-letter-queues (DLQs) or error destinations, but there are so many ways to do it I often find myself needing to look them up. So, I thought it might be useful to have a simple guide. Here it is.

To make this easier to use quickly I’m including a quick reference table for each integration or integration type. The table will look something like this:

Retries DLQ at integration DLQ at function Error destination at function
✅ Up to 2* ✅ Service dependent ✅ Yes ✅ Yes

I’ll do my best to include more information when necessary. An asterisk marks a default retry policy explained below the table. In these tables, DLQ at integration includes failure storage and destinations on an event source mapping or the source service. At function refers to Lambda’s asynchronous invocation settings; those settings don’t apply to synchronous calls or event source mappings.

Asynchronous or Synchronous

There are two ways to invoke a Lambda function. The type of invocation is key to how you handle errors and retries. Understanding the difference between asynchronous and synchronous invocations will help you narrow down the options pretty quickly.

Asynchronous Invocations

Retries DLQ at integration DLQ at function Error destination at function
✅ Up to 2* ✅ Service dependent ✅ Yes ✅ Yes

For asynchronous invocations, Lambda queues the event internally and retries function errors twice by default, waiting one minute before the first retry and two minutes before the second. You can configure zero, one, or two retries. Throttling and system errors follow a separate backoff policy, with retries for up to six hours by default; the two-retry limit does not apply to those failures. Events can be delivered more than once, so make your handler safe to run again for the same event.

You can configure a function DLQ or an on-failure destination to retain events that exhaust retries or expire. A DLQ receives the original event with error attributes; a destination receives an invocation record with request and response details. DLQs support SQS and SNS. On-failure destinations also support Lambda, EventBridge, and S3.

There are two different failure points here: delivery to Lambda and processing by your function. Some sources have their own retries and DLQs for delivery failures, including EventBridge rule targets and SNS subscriptions. Once Lambda accepts an event, function errors are handled by Lambda’s asynchronous retry and failure settings, not by the source’s delivery DLQ.

The following are examples of integrations that asynchronously invoke your Lambda function. This is not an exhaustive list of every Lambda integration.

AWS IoT Events appeared in the original version of this list, but the service shut down on May 20, 2026.

Synchronous Invocations

For synchronous invocations you won’t get a DLQ or error destination at the function itself. For these integrations it’s up to the caller to handle retries and errors, so you may get retries and DLQs in some cases, but not others.

When you invoke a function synchronously, Lambda runs the function and waits for a response. When the function completes, Lambda returns the response from the function’s code with additional data, such as the version of the function that was invoked.

If Lambda isn’t able to run the function, the error is displayed in the output.

Here is a list of each integration and how its retries and DLQs work.

CLI & SDK

Retries DLQ at integration DLQ at function Error destination at function
✅ Some ❌ No ❌ No ❌ No

CLI & SDK invocations can call your function either synchronously or asynchronously. The table describes synchronous calls: SDK retry settings can retry some request failures, but function errors returned in a successful Invoke API response require caller handling. Calls using InvocationType: Event follow the asynchronous behavior above after Lambda accepts the event.

API Gateway

Retries DLQ at integration DLQ at function Error destination at function
❌ None ❌ No ❌ No ❌ No

API Gateway normally invokes your function synchronously. It does not retry Lambda invocations, and the integration does not support a DLQ. REST API non-proxy integrations can also be configured for asynchronous invocation; those calls follow Lambda’s asynchronous retry settings after acceptance.

Cognito (except custom sender triggers)

Retries DLQ at integration DLQ at function Error destination at function
✅ Some retryable failures ❌ No ❌ No ❌ No

Cognito invokes your function synchronously except for custom sender triggers.

The function must respond within five seconds. Cognito may retry eligible calls that do not respond in time, but this is not a blanket guarantee of two retries. Cognito does not retry Invoke errors with HTTP status codes 500–599.

DynamoDB Streams

Retries DLQ at integration DLQ at function Error destination at function
✅ Until expiry* ✅ On mapping ❌ No ❌ No

DynamoDB Streams invoke your function synchronously in batches. If the function returns an error or times out the entire batch will be retried until the message expires by default. The integration is an event source mapping, which includes several configuration options to control retries and failure destinations. The failure destination belongs to the event source mapping, not the function’s asynchronous invocation settings.

  • BisectBatchOnFunctionError allows you to isolate a single record that is causing a problem. Every error will result in splitting the batch in order to isolate the error. These retries do not count toward the MaximumRetryAttempts.
  • DestinationConfig supports an on-failure destination such as SQS, SNS, or S3. SQS and SNS receive metadata about the failed batch; S3 also retains the invocation payload, which is useful for replay after stream records expire.
  • MaximumRetryAttempts controls the number of retries after a function error before the record is discarded (or sent to a failure destination if configured). The default value is -1, which retries until the record expires.
  • MaximumRecordAgeInSeconds can bound how long Lambda keeps retrying a record. Source retention still applies.
  • ReportBatchItemFailures lets your handler report a failed sequence number so retries resume at the earliest failed record, rather than automatically retrying the whole batch. Enable it on the mapping and return the required response from your code.

DynamoDB Streams retains records for 24 hours. See the current DynamoDB failure handling and destination guidance.

Elastic Load Balancing - Application Load Balancer

Retries DLQ at integration DLQ at function Error destination at function
❌ No ❌ No ❌ No ❌ No

Application Load Balancer invokes your function synchronously. There are no retries when making calls to your function, and the integration does not support a DLQ.

Amazon Data Firehose (formerly Kinesis Firehose)

Retries DLQ at integration DLQ at function Error destination at function
✅ User controlled ✅ S3 failure output ❌ No ❌ No

Amazon Data Firehose calls your function synchronously. You can configure the retry count; the default is three retries for invocation failures such as network timeouts or invocation limits. There is no Lambda DLQ, but Firehose writes unsuccessfully processed records to S3 under processing-failed. See Firehose transformation failure handling.

Kinesis Streams

Retries DLQ at integration DLQ at function Error destination at function
✅ Until expiry* ✅ On mapping ❌ No ❌ No

Kinesis Streams invoke your function synchronously in batches. If the function returns an error or times out the entire batch will be retried until the message expires by default. The integration is an event source mapping, which includes several configuration options to control retries and failure destinations.

  • BisectBatchOnFunctionError allows you to isolate a single record that is causing a problem. Every error will result in splitting the batch in order to isolate the error. These retries do not count toward the MaximumRetryAttempts.
  • DestinationConfig supports an on-failure destination such as SQS, SNS, or S3. SQS and SNS receive metadata about the failed batch; S3 also retains the invocation payload, which is useful for replay after stream records expire.
  • MaximumRetryAttempts controls the number of retries after a function error before the record is discarded (or sent to a failure destination if configured). The default value is -1, which retries until the record expires.
  • MaximumRecordAgeInSeconds can bound how long Lambda keeps retrying a record. Source retention still applies.
  • ReportBatchItemFailures lets your handler report a failed sequence number so retries resume at the earliest failed record, rather than automatically retrying the whole batch. Enable it on the mapping and return the required response from your code.

Kinesis retention is configured on the stream. See the mapping parameters and failure destination guidance.

Lex

Retries DLQ at integration DLQ at function Error destination at function
❌ None ❌ No ❌ No ❌ No

Lex V2 invokes your function synchronously. There are no retries when making calls to your function, and the integration does not support a DLQ.

Amazon MQ

Retries DLQ at integration DLQ at function Error destination at function
✅ Until success or expiry ✅ Broker dependent ❌ No ❌ No

Amazon MQ invokes your function synchronously through an event source mapping. If a batch fails, Lambda retries the whole batch until it succeeds or the messages expire. The mapping does not expose the stream-style retry limits or on-failure destinations. Broker dead-letter behavior is configured separately; do not assume a broker DLQ replaces Lambda’s batch retry handling.

S3 Batch

Retries DLQ at integration DLQ at function Error destination at function
✅ Yes ❌ No ❌ No ❌ No

S3 Batch invokes your function synchronously. There is no option for a DLQ. If the Lambda function returns a TemporaryFailure response code, Amazon S3 retries the operation.

SQS

Retries DLQ at integration DLQ at function Error destination at function
✅ Configured in SQS ✅ On source queue ❌ No ❌ No

SQS invokes your function synchronously through an event source mapping. Configure a redrive policy on the source queue, with a DLQ and maxReceiveCount. Failed messages become visible again after the visibility timeout and can be received again; the redrive policy moves repeatedly received messages to the DLQ. Without a DLQ, messages remain subject to the queue’s retention period rather than being discarded at a configured retry count.

By default, a failed batch makes even successfully processed messages available again. Enable ReportBatchItemFailures on the mapping and return failed message IDs from your handler to retry only those messages. For FIFO queues, stop after the first failure and report failed and unprocessed messages to preserve ordering. See SQS error handling and partial batch responses.

Lambda backs off when function errors or throttling occur. Throttled invocations are retried within the visibility timeout; subsequent receives and the queue’s redrive policy govern further attempts. These are separate from Lambda’s asynchronous two-retry setting.

Step Functions (synchronous invoke)

Retries DLQ at integration DLQ at function Error destination at function
✅ Controlled in retry configuration ✅ Explicit failure-handling state ❌ No ❌ No

Step Functions can invoke a Lambda synchronously. When doing so you can use the retry setting to control the retries. Any error logic can be handled in the state machine using the catch setting and sending the message to an SQS queue or SNS topic within the state machine itself.

Updated Originally published