What Is AWS Lambda?
AWS Lambda is a serverless computing service that runs application code without requiring developers to provision or manage servers. You deploy a function, configure its runtime, memory, permissions, and event sources, and AWS executes the code when it is invoked. Lambda automatically manages the underlying execution environments and scales the number of concurrent executions as demand changes, subject to service quotas and configured limits.
Lambda is commonly used for HTTP APIs, background jobs, file processing, scheduled tasks, and event-driven integrations. It can simplify infrastructure operations and reduce idle compute costs, but it introduces its own engineering challenges: cold starts, execution time limits, concurrency management, retries, duplicate events, and connections to downstream services. Understanding these behaviors is essential before using Lambda in production.
Table of Contents
- AWS Lambda Fundamentals
- How AWS Lambda Works
- Lambda Invocation and Event Sources
- Concurrency, Scaling, and Performance
- Lambda Pricing and Security
- Production Design Example
- Ready-to-Use Example: AWS Lambda with SQS and Terraform
- Production Best Practices and Common Mistakes
- Frequently Asked Questions
- Conclusion
AWS Lambda Fundamentals
Traditional applications often run as long-lived processes on servers or containers. Even when traffic is low, those processes typically remain active and their infrastructure continues consuming resources. Lambda uses a different execution model: code is invoked in response to requests or events, and AWS manages the execution environments needed to process them.
A Lambda function consists of application code and configuration, including the runtime, handler, memory allocation, timeout, environment variables, execution role, and optional networking settings. The same function can be invoked by multiple supported AWS services.
What Serverless Actually Means
Serverless does not mean that physical servers disappear. Lambda code still executes on AWS-managed infrastructure. The difference is that developers do not directly manage the servers, operating system provisioning, or most of the compute capacity lifecycle.
With Lambda, AWS handles execution environment provisioning, infrastructure-level scaling, and much of the underlying maintenance. Your team remains responsible for application code, dependencies, IAM permissions, configuration, observability, and reliable handling of failures.
This distinction matters because a serverless application can still experience outages caused by exhausted database connections, insufficient concurrency quotas, incorrect permissions, or poorly designed event processing.
Lambda vs. EC2 and Containers
Lambda is one of several AWS compute options. Choosing between Lambda, EC2, and container services depends on workload duration, traffic patterns, operational requirements, and the level of runtime control needed.
| Characteristic | AWS Lambda | Amazon EC2 | ECS with Fargate |
|---|---|---|---|
| Compute model | Event-driven function invocations | Virtual machines | Managed container execution |
| Server management | AWS-managed | Customer-managed guest OS | AWS-managed hosts |
| Execution duration | Limited per invocation | Long-running processes | Long-running services and tasks |
| Scaling | Automatic invocation concurrency | Manual or Auto Scaling groups | Service Auto Scaling |
| Best suited for | Events, APIs, short jobs | Custom server workloads | Containerized applications |
Lambda can be an excellent fit for unpredictable or intermittent traffic. EC2 and containers may be more suitable for consistently busy services, workloads that require specialized operating system access, or processes that exceed Lambda's execution limits.
For a broader architectural comparison, read Virtual Machines vs Containers vs Serverless.
Common Lambda Use Cases
Lambda is particularly useful when application work can be represented as independently executable units triggered by an event or request.
- HTTP APIs: Process requests through Amazon API Gateway or supported HTTP integrations.
- File processing: Generate image thumbnails or extract document metadata after S3 uploads.
- Queue consumers: Process messages from Amazon SQS.
- Scheduled jobs: Run cleanup tasks, reports, or maintenance operations using EventBridge Scheduler.
- Database events: React to supported DynamoDB Streams changes.
- Event integrations: Process application and AWS service events routed through EventBridge.
- Automation: Perform small infrastructure or operational workflows.
Lambda is less attractive when individual tasks run for hours, require a persistent connection throughout their lifetime, or depend on local state surviving between invocations.
How AWS Lambda Works
When Lambda receives an invocation, it selects or creates an execution environment with the function's code, runtime, dependencies, and configured resources. The runtime invokes the designated handler with the event payload and context information.
The execution environment may be reused for subsequent invocations, but reuse is not guaranteed. Applications must therefore work correctly whether a request runs in a new environment or one that previously handled other requests.
Functions, Handlers, and Events
A Lambda handler is the entry point for function execution. In Python, the handler commonly accepts an event dictionary and a context object.
Create a file named handler.py:
import json
import logging
import os
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
SERVICE_NAME = os.getenv("SERVICE_NAME", "example")
def lambda_handler(event, context):
# Read the input supplied by the invoking service.
name = event.get("name", "world")
logger.info(
"Processing request: request_id=%s",
context.aws_request_id,
)
# Return a JSON-serializable response.
return {
"service": SERVICE_NAME,
"message": f"Hello, {name}!",
"request_id": context.aws_request_id,
}
The handler name is configured as handler.lambda_handler, which identifies the Python module and function.
The event structure depends on the invocation source. An API Gateway request contains HTTP-specific fields, while an SQS invocation contains a batch of message records. Production code should validate the expected event schema instead of assuming all Lambda events have the same structure.
Execution Environments and Lifecycle
A Lambda execution environment has an initialization phase and an invocation phase. During initialization, the runtime loads application code and executes initialization statements outside the handler.
For example, creating a boto3 client outside the handler allows subsequent invocations in the same environment to reuse that client:
import boto3
# Initialize reusable SDK clients outside the handler.
s3 = boto3.client("s3")
def lambda_handler(event, context):
bucket = event["bucket"]
key = event["key"]
# Reuse the client when the environment is warm.
metadata = s3.head_object(
Bucket=bucket,
Key=key,
)
return {
"size": metadata["ContentLength"],
"content_type": metadata.get("ContentType"),
}
Client reuse can reduce repeated initialization overhead. Database connections, HTTP clients, and other resources can also be reused when they are safe to share between sequential invocations.
However, cached connections may become stale. Applications should handle connection failures and reconnect when necessary. Never rely on in-memory variables for durable business state.
For more detail, read AWS Lambda Execution Lifecycle Explained.
Cold Starts and Environment Reuse
A cold start occurs when Lambda must initialize a new execution environment before running the handler. Initialization can include starting the runtime, loading dependencies, executing module-level code, and establishing initial connections.
Cold starts are more noticeable when functions have large dependency packages, expensive initialization logic, or workloads that frequently require new environments.
Common ways to reduce initialization overhead include:
- Keep deployment packages and imported dependencies reasonably small.
- Initialize only resources required for the current function.
- Reuse SDK clients and safe network connections across invocations.
- Avoid unnecessary network calls during module initialization.
- Use provisioned concurrency for latency-sensitive workloads when justified.
- Evaluate SnapStart where supported by the runtime and configuration.
Cold starts are not necessarily a problem for asynchronous background jobs. An extra initialization delay may be acceptable when processing queued work, while the same delay could violate latency objectives for a synchronous API.
See AWS Lambda Cold Starts Explained for a deeper look at initialization latency.
Lambda Invocation and Event Sources
Lambda supports different invocation models, and each model has distinct retry, error-handling, and scaling behavior. These differences are important because a failed synchronous API request should not be handled in the same way as a failed background queue message.
Understanding who owns retries and where events are buffered is one of the most important parts of designing reliable Lambda applications.
Synchronous, Asynchronous, and Poll-Based Invocation
There are three common invocation patterns:
| Invocation | Behavior | Examples |
|---|---|---|
| Synchronous | Caller waits for a response | API Gateway, direct RequestResponse invocation |
| Asynchronous | Lambda queues the event for later execution | EventBridge, S3 notifications to Lambda |
| Poll-based | Lambda polls an external event source | SQS, DynamoDB Streams, Kinesis |
For synchronous invocation, the caller generally receives the function result or error and is responsible for deciding whether to retry.
For asynchronous invocation, Lambda manages an internal event queue and retry behavior. Poll-based integrations have their own source-specific retry and checkpointing semantics.
Common AWS Event Sources
Lambda integrates with many AWS services, but not all integrations deliver events in the same way.
- Amazon API Gateway: Routes HTTP requests to Lambda and returns responses to clients.
- Amazon S3: Can invoke Lambda when supported object events occur.
- Amazon SQS: Lambda polls messages and invokes functions with batches.
- Amazon EventBridge: Routes application and AWS service events to functions.
- Amazon DynamoDB Streams: Supplies records representing item changes.
- Amazon Kinesis: Supplies streaming records through event source mappings.
- EventBridge Scheduler: Invokes functions on configured schedules.
An SQS event source mapping is especially useful for decoupling application components. Producers enqueue work without waiting for the consumer to complete processing.
Read AWS Lambda Event Sources Explained and What Is a Message Queue?.
Retries, Duplicate Events, and Failure Handling
Lambda applications must account for retries and duplicate deliveries. For example, an SQS message may be delivered again if processing fails or its visibility timeout expires before successful completion.
A function that sends an email, charges a payment, or creates a database record should not assume that each business event will be processed exactly once.
Idempotency is a practical solution. A consumer uses a stable business identifier to detect whether the operation has already completed and avoids repeating its side effects.
For SQS integrations, partial batch responses allow a handler to report individual failed message IDs instead of retrying every message in a batch. A dead-letter queue can retain messages that repeatedly fail processing.
See What Is an Idempotency Key?, What Is a Dead Letter Queue?, and Dead-Letter Queues, Retries, and Poison Messages.
Concurrency, Scaling, and Performance
Lambda automatically adjusts execution capacity in response to demand, but scaling is governed by concurrency quotas, per-function scaling behavior, and event-source-specific limits.
More concurrency is not always better. A function that scales rapidly can overwhelm databases, third-party APIs, or other downstream services that have lower capacity limits.
Understanding Lambda Concurrency
Concurrency is the number of invocations executing at the same time. For a workload with relatively stable request rates and durations, an approximate concurrency requirement is:
Concurrency = Requests per second × Average execution duration in seconds
For example, if a function receives 500 requests per second and each invocation runs for 200 milliseconds:
Concurrency = 500 × 0.2 = 100 concurrent executions.
If execution time increases to one second while traffic remains constant, concurrency rises to approximately 500. Slower downstream services can therefore increase Lambda concurrency even when incoming traffic does not change.
Lambda also has requests-per-second and scaling-rate limits, so concurrency alone is not sufficient for every capacity estimate. AWS documents these controls in its Lambda concurrency documentation.
Reserved and Provisioned Concurrency
Lambda provides two important concurrency controls:
- Reserved concurrency: Reserves a portion of account concurrency for a function and sets a maximum concurrency limit for that function.
- Provisioned concurrency: Maintains a configured number of initialized execution environments to reduce initialization latency.
Reserved concurrency can protect downstream services. For example, limiting a database-writing function to 20 concurrent executions can prevent uncontrolled connection growth during traffic spikes.
Provisioned concurrency is primarily a latency optimization and incurs additional charges. It is useful when predictable response latency matters enough to justify keeping execution environments initialized.
Neither setting eliminates the need to monitor throttling, invocation duration, and downstream capacity.
For detailed scaling behavior, read AWS Lambda Concurrency and Scaling.
Memory, CPU, and Execution Limits
Lambda allocates CPU capacity proportionally to configured memory. Increasing memory can improve performance even when a function does not require the additional memory for data storage.
For CPU-intensive functions, higher memory allocation may reduce execution duration enough to offset some or all of the increased per-unit compute price.
Important configuration limits include:
- Timeout: A function invocation has a configurable maximum duration of 15 minutes.
- Memory: Lambda supports configurable memory allocation within its supported service range.
- Temporary storage: The
/tmpdirectory provides configurable ephemeral storage. - Deployment size: ZIP packages, layers, and container images have separate size constraints.
- Concurrency: Regional account quotas and function-level controls restrict simultaneous execution.
Functions should set realistic timeouts and use network timeouts shorter than the remaining invocation time. A function that waits indefinitely for an external API may consume concurrency without making progress.
For optimization techniques, see AWS Lambda Performance Optimization.
Lambda Pricing and Security
Lambda is often cost-effective for intermittent workloads because standard on-demand execution charges are tied to requests and compute duration rather than continuously running virtual machines.
However, total cost also depends on memory allocation, architecture, provisioned concurrency, logging, network traffic, and services invoked by the function.
How Lambda Pricing Works
For standard on-demand functions, the main pricing dimensions include:
- Requests: Number of function invocations.
- Compute duration: Execution duration multiplied by allocated memory.
- Provisioned concurrency: Additional charges when pre-initialized capacity is configured.
- Additional resources: Certain storage, logging, networking, and related service usage.
Consider a function receiving one million requests per month. If each invocation runs for 200 milliseconds with 512 MB of memory, the approximate compute usage is:
1,000,000 × 0.2 seconds × 0.5 GB = 100,000 GB-seconds.
This is a usage calculation, not a price quote. Actual billing depends on the current AWS pricing model, applicable free allowances, architecture, and additional features.
For frequently invoked, long-running workloads, compare Lambda's total cost against ECS Fargate or EC2 rather than assuming serverless is always cheaper.
IAM Roles, Secrets, and VPC Networking
Every Lambda function uses an execution role that defines which AWS resources its code can access. For example, an image-processing function may need permission to read objects from one S3 bucket and write results to another.
Use least-privilege permissions and avoid wildcard access when specific resources can be identified.
For sensitive configuration, prefer AWS Secrets Manager or Systems Manager Parameter Store over hardcoded credentials. Environment variables can contain configuration values, but access to sensitive values still needs appropriate controls.
Lambda can also be configured to access resources in a VPC. This is useful for private databases or internal services, but the selected subnets, security groups, and network routes must support the required connectivity.
A Lambda function attached to a VPC does not automatically gain public internet access. If it needs outbound access, configure appropriate routing through NAT or supported VPC endpoints.
For related security guidance, see Secrets Management in Cloud Applications.
Production Design Example
Consider a media application where users upload images and expect multiple optimized variants. The system stores originals in Amazon S3 and generates thumbnails and resized versions asynchronously.
The application must handle bursts of uploads, processing failures, duplicate events, and large files without blocking user-facing API requests.
Asynchronous Image Processing Architecture
A production design can use the following components:
- FastAPI backend: Authenticates users and creates upload records.
- Amazon S3: Stores original images and generated variants.
- Amazon EventBridge or S3 notifications: Publishes object-created events.
- Amazon SQS: Buffers image-processing jobs.
- AWS Lambda: Downloads originals, validates images, and generates variants.
- Amazon DynamoDB or PostgreSQL: Tracks processing status and file metadata.
- Amazon CloudFront: Delivers processed images efficiently.
When an upload completes, an event reaches SQS. Lambda polls the queue and processes the image. The original upload request does not wait for image conversion to finish.
Using SQS between S3 events and Lambda provides buffering and gives the system control over processing concurrency. If 10,000 images arrive within a short period, the queue can absorb the burst while Lambda processes messages at a sustainable rate.
For larger images or expensive processing, memory allocation, temporary storage, timeout, and concurrency should be measured under realistic workloads.
Failure Scenario: Duplicate Events and Database Saturation
Suppose an image upload produces a processing event, but the worker completes the image conversion and then fails before acknowledging the message. SQS may deliver the message again.
Without idempotency, the worker may regenerate files unnecessarily, duplicate database records, or trigger repeated downstream notifications.
A robust design uses a stable processing identifier, such as the object key and version ID, together with a conditional database update. The worker checks whether the specific image version has already been processed before committing final results.
A second failure occurs when Lambda concurrency increases rapidly and each invocation opens several database connections. The database may become saturated even though Lambda itself continues scaling successfully.
Limit processing concurrency, reuse connections when appropriate, and use connection pooling or an appropriate database proxy. See What Is Connection Pooling? and Background Workers Explained: Designing Reliable Asynchronous Processing.
Ready-to-Use Example: AWS Lambda with SQS and Terraform
This example creates a Python Lambda function that processes messages from an Amazon SQS queue. Terraform provisions the queue, a dead-letter queue, an IAM execution role, the Lambda function, and an event source mapping.
The function logs incoming messages and supports partial batch failure reporting. The example demonstrates reliable event consumption without requiring a public API endpoint or a continuously running server.
1. Project Structure and Prerequisites
Install Terraform, Python 3, and the AWS CLI. Configure AWS credentials with permissions to create Lambda, IAM, SQS, and CloudWatch resources.
Create a directory with the following structure:
lambda-sqs-demo/
main.tf
outputs.tf
handler.py
The example uses Python's standard library for message processing, so no third-party dependencies need to be packaged.
2. Implement the Python Lambda Handler
Create handler.py:
import json
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
def process_message(body: dict) -> None:
# Validate the required business fields.
job_id = body.get("job_id")
action = body.get("action")
if not isinstance(job_id, str) or not job_id:
raise ValueError("Missing job_id")
if action not in {"resize", "thumbnail"}:
raise ValueError("Unsupported action")
# Replace this log with real processing logic.
# Production side effects must be idempotent.
logger.info(
"Processed job_id=%s action=%s",
job_id,
action,
)
def lambda_handler(event, context):
failed = []
for record in event.get("Records", []):
message_id = record["messageId"]
try:
# SQS message bodies are strings.
body = json.loads(record["body"])
if not isinstance(body, dict):
raise ValueError(
"Expected a JSON object"
)
process_message(body)
except (ValueError, TypeError) as exc:
# Report invalid messages for retry.
logger.warning(
"Invalid message %s: %s",
message_id,
exc,
)
failed.append({
"itemIdentifier": message_id
})
except Exception:
# Unexpected failures must not be lost.
logger.exception(
"Failed to process message %s",
message_id,
)
failed.append({
"itemIdentifier": message_id
})
# Only failed messages are retried when the
# event source mapping enables partial responses.
return {
"batchItemFailures": failed
}
The handler processes each message independently and returns identifiers for failed messages. Successful messages can be removed from the queue without waiting for the entire batch to succeed.
This example validates and logs messages; it does not persist processing results. A production implementation must add durable idempotency protection before performing non-repeatable side effects.
3. Provision AWS Resources with Terraform
Create main.tf:
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
archive = {
source = "hashicorp/archive"
version = "~> 2.0"
}
}
}
provider "aws" {
region = "us-west-2"
}
# Package the Python handler as a ZIP artifact.
data "archive_file" "lambda" {
type = "zip"
source_file = "${path.module}/handler.py"
output_path = "${path.module}/lambda.zip"
}
# Store messages that repeatedly fail processing.
resource "aws_sqs_queue" "dlq" {
name = "lambda-demo-dlq"
}
resource "aws_sqs_queue" "jobs" {
name = "lambda-demo-jobs"
# Six times the Lambda timeout in this example.
visibility_timeout_seconds = 180
# Retain messages for up to four days.
message_retention_seconds = 345600
redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.dlq.arn
maxReceiveCount = 5
})
}
# Allow Lambda to assume the execution role.
data "aws_iam_policy_document" "trust" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["lambda.amazonaws.com"]
}
}
}
resource "aws_iam_role" "lambda" {
name_prefix = "lambda-sqs-demo-"
assume_role_policy = data.aws_iam_policy_document.trust.json
}
# Grant permission to write CloudWatch logs.
resource "aws_iam_role_policy_attachment" "logs" {
role = aws_iam_role.lambda.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
# Grant permissions for polling the specific queue.
resource "aws_iam_role_policy" "sqs" {
name = "read-demo-queue"
role = aws_iam_role.lambda.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = [
"sqs:ReceiveMessage",
"sqs:DeleteMessage",
"sqs:GetQueueAttributes"
]
Resource = aws_sqs_queue.jobs.arn
}]
})
}
# Create the Lambda function.
resource "aws_lambda_function" "worker" {
function_name = "lambda-sqs-demo-worker"
role = aws_iam_role.lambda.arn
runtime = "python3.12"
handler = "handler.lambda_handler"
filename = data.archive_file.lambda.output_path
source_code_hash = data.archive_file.lambda.output_base64sha256
timeout = 30
memory_size = 256
# Protect downstream systems from excessive
# simultaneous processing.
reserved_concurrent_executions = 5
depends_on = [
aws_iam_role_policy_attachment.logs,
aws_iam_role_policy.sqs
]
}
# Poll SQS and invoke the worker with batches.
resource "aws_lambda_event_source_mapping" "jobs" {
event_source_arn = aws_sqs_queue.jobs.arn
function_name = aws_lambda_function.worker.arn
batch_size = 5
enabled = true
# Retry only the failed message identifiers.
function_response_types = [
"ReportBatchItemFailures"
]
# Limit concurrency for this queue.
scaling_config {
maximum_concurrency = 5
}
}
The SQS visibility timeout is 180 seconds, six times the Lambda function's 30-second timeout. This follows AWS's general guidance for allowing time for processing and retries when configuring SQS event source mappings.
The function's reserved concurrency and the event source mapping's maximum concurrency are both five. In production, coordinate these limits carefully when multiple event sources invoke the same function.
The queue's redrive policy moves messages to the dead-letter queue after repeated unsuccessful receives. A DLQ is not a replacement for alerting or investigation; failed messages still need an operational recovery process.
Create outputs.tf:
output "queue_url" {
description = "URL of the source SQS queue."
value = aws_sqs_queue.jobs.url
}
output "dlq_url" {
description = "URL of the dead-letter queue."
value = aws_sqs_queue.dlq.url
}
output "function_name" {
description = "Lambda function name."
value = aws_lambda_function.worker.function_name
}
4. Deploy and Send Test Messages
Initialize and apply the Terraform configuration:
# Initialize the providers.
terraform init
# Format and validate configuration.
terraform fmt
terraform validate
# Review the infrastructure changes.
terraform plan
# Create the Lambda function and queues.
terraform apply
# Export the queue URL for testing.
QUEUE_URL="$(terraform output -raw queue_url)"
# Send a valid message.
aws sqs send-message \
--queue-url "$QUEUE_URL" \
--message-body '{"job_id":"job-001","action":"resize"}'
# Send another valid message.
aws sqs send-message \
--queue-url "$QUEUE_URL" \
--message-body '{"job_id":"job-002","action":"thumbnail"}'
# Send an invalid message to test retries.
aws sqs send-message \
--queue-url "$QUEUE_URL" \
--message-body '{"job_id":"job-003","action":"unknown"}'
The Lambda event source mapping polls the queue automatically. Valid messages should be processed successfully, while the invalid message should be retried and eventually moved to the dead-letter queue after reaching the configured receive threshold.
SQS processing is asynchronous. Messages may not be processed immediately, and their order is not guaranteed for this standard queue.
5. Monitor and Clean Up
Inspect Lambda logs and the dead-letter queue:
# Follow Lambda execution logs.
FUNCTION="$(terraform output -raw function_name)"
aws logs tail \
"/aws/lambda/$FUNCTION" \
--follow
# In another terminal, inspect DLQ attributes.
DLQ_URL="$(terraform output -raw dlq_url)"
aws sqs get-queue-attributes \
--queue-url "$DLQ_URL" \
--attribute-names \
ApproximateNumberOfMessages \
ApproximateNumberOfMessagesNotVisible
# Remove the demonstration infrastructure.
terraform destroy
CloudWatch log streams may take a short time to appear after the first invocation. The DLQ's approximate message count may also take time to reflect failed messages.
Destroying the infrastructure deletes the demo queues and any remaining messages. In production, never delete a queue or DLQ without reviewing retention and recovery requirements.
Production Best Practices and Common Mistakes
Lambda removes much of the server-management burden, but production operations still require careful attention to reliability, security, and observability. The most common problems involve event retries, unexpected concurrency, slow dependencies, and insufficient visibility into failures.
Good Lambda architecture starts by defining what happens when an invocation fails, times out, or executes more than once.
Logging, Metrics, and Observability
CloudWatch provides standard Lambda metrics such as invocations, errors, duration, throttles, and concurrent executions. Additional metrics are available for some configurations and event source integrations.
Useful operational signals include:
- Error rate: Number and percentage of failed invocations.
- Duration: Execution time, especially high percentiles.
- Throttles: Requests that cannot execute because of concurrency constraints.
- Concurrent executions: Capacity consumption over time.
- Queue age: Time the oldest unprocessed message has waited.
- DLQ depth: Messages requiring investigation or recovery.
- Initialization duration: Cold-start overhead when measurable.
Use structured logs with correlation identifiers such as request IDs, job IDs, or event IDs. Avoid logging credentials, full authorization headers, or sensitive event payloads.
For distributed workflows, tracing can connect API requests, queue messages, and Lambda processing. See Observability Explained: Logs, Metrics, and Traces.
Common Lambda Mistakes
Several implementation mistakes repeatedly cause reliability or performance issues:
- Assuming exactly-once execution: Retries create duplicate business side effects.
- Using global memory as durable state: Data disappears when an execution environment is recycled.
- Opening database connections without limits: Rapid scaling exhausts database capacity.
- Ignoring timeouts: Slow dependencies consume concurrency until invocations fail.
- Using oversized deployment packages: Initialization and deployment become more expensive or slower.
- Giving functions broad IAM permissions: A compromised function can access unrelated resources.
- Ignoring DLQ messages: Failed jobs accumulate without recovery.
- Using Lambda for unsuitable long-running workloads: Jobs exceed execution limits or require persistent processes.
- Confusing reserved and provisioned concurrency: Reserved concurrency alone does not pre-initialize environments.
For failure recovery patterns, see Timeouts, Retries, and Exponential Backoff and Handling Partial Failures in Production Systems.
Production Checklist
Before deploying a Lambda workload to production, verify the following:
- Function timeouts reflect realistic execution requirements.
- Memory and CPU allocation are measured under representative workloads.
- Handlers validate incoming event schemas.
- Retryable operations are idempotent.
- Queue visibility timeouts and batch settings are configured correctly.
- DLQs or failure destinations are configured where appropriate.
- Reserved concurrency protects downstream capacity when needed.
- IAM permissions are restricted to required resources and actions.
- Secrets and credentials are handled securely.
- Logging, tracing, metrics, and alarms support incident investigation.
- Deployment packages and dependencies are reproducible.
- Rollback and event replay procedures are documented and tested.
For more production guidance, read AWS Lambda Best Practices for Production.
Frequently Asked Questions
AWS Lambda is a common starting point for serverless applications, but it is important to distinguish its managed execution model from the behavior of traditional servers and container platforms.
What Is AWS Lambda Used For?
AWS Lambda runs code in response to events or requests. Common use cases include APIs, file processing, queue consumers, scheduled tasks, notifications, and integrations between AWS services.
Does AWS Lambda Run on a Server?
Yes. Lambda runs on AWS-managed computing infrastructure. The term serverless means developers do not directly provision and maintain the servers that execute their functions.
Is AWS Lambda Free?
AWS Lambda has applicable free usage allowances for eligible workloads and accounts. Beyond those allowances, charges depend on requests, compute duration, allocated memory, and optional features such as provisioned concurrency.
Related AWS services, including CloudWatch, SQS, API Gateway, and network infrastructure, may have separate charges.
How Long Can a Lambda Function Run?
A single Lambda invocation can run for up to 15 minutes. Functions that require longer execution times may be better suited to ECS tasks, AWS Batch, EC2, or a workflow that divides work into smaller steps.
Can AWS Lambda Host a REST API?
Yes. Lambda can handle HTTP requests through Amazon API Gateway, Lambda Function URLs, or supported load balancer integrations.
Frameworks such as FastAPI can also run on Lambda using an appropriate adapter, although the application must account for the Lambda invocation model, startup behavior, and deployment constraints.
Can Lambda Connect to a Database?
Yes. Lambda functions can connect to relational databases, DynamoDB, and other supported data stores when networking and permissions are configured correctly.
For relational databases, control concurrency and connection usage carefully. RDS Proxy or application-level pooling may help manage connection pressure, depending on the architecture.
When Should I Use Lambda Instead of EC2?
Lambda is a good choice for event-driven, short-lived, and intermittently active workloads where minimizing server management is valuable.
EC2 may be more suitable when applications need full operating system control, specialized hardware, long-running processes, or predictable high utilization that makes dedicated compute more economical.
Conclusion
AWS Lambda is a serverless computing service that allows developers to run application code without managing the underlying servers. It integrates with AWS services, automatically adjusts execution capacity, and supports event-driven architectures ranging from small automation tasks to production APIs and asynchronous processing systems.
Its operational simplicity does not eliminate distributed systems challenges. Lambda applications must handle retries, duplicate events, execution limits, cold starts, concurrency quotas, and downstream bottlenecks. Reliable implementations combine idempotent handlers, appropriate concurrency controls, secure IAM roles, observable execution, and carefully designed failure recovery.
Key Takeaway: AWS Lambda is most effective when work can be divided into independent, bounded executions. Use it to simplify compute operations, but design event delivery, state management, scaling, and recovery as deliberately as you would in any distributed system.
More Articles to Read
Continue exploring the AWS Lambda series and related articles about serverless architecture, event-driven processing, cloud infrastructure, and production reliability.
Comments (0)