AWS Lambda — Complete Serverless Functions Guide
In this tutorial, you will learn about AWS Lambda. We cover key concepts, practical examples, and best practices to help you master this topic.
AWS Lambda is Amazon's FaaS platform that runs your code in response to events from over 200 AWS services with automatic scaling and pay-per-execution pricing.
What You'll Learn
By the end of this lesson you will understand how to create, configure, and deploy AWS Lambda functions, set up triggers, manage IAM permissions, and monitor execution.
Why It Matters
Lambda is the most mature and widely adopted serverless platform. Understanding Lambda unlocks serverless architecture patterns used by thousands of production systems including Netflix, Airbnb, and DodaTech's own file processing pipeline.
Real-World Use
Doda Browser uses Lambda to scan uploaded files for malware. An S3 upload event triggers a Lambda function that downloads the file, runs signature-based and heuristic detection, quarantines threats, and logs results -- all without any server infrastructure.
flowchart TD
U[Upload File to S3] --> E[S3 Event Notification]
E --> L[AWS Lambda]
L --> D[Download File]
D --> S[Scan for Malware]
S -->|Clean| T[Tag as Safe]
S -->|Threat| Q[Quarantine]
T --> N[SNS Notification]
Q --> A[Admin Alert]
style L fill:#f90,color:#fff
Creating a Lambda Function
Lambda functions consist of your code, a runtime (Node.js, Python, Java, etc.), IAM permissions, and optional configuration like memory and timeout.
# lambda_basic.py
# A basic AWS Lambda function
import json
def lambda_handler(event, context):
"""Entry point for AWS Lambda."""
http_method = event.get("httpMethod", "GET")
path = event.get("path", "/")
query = event.get("queryStringParameters", {}) or {}
print(f"Processing {http_method} {path}")
print(f"Query params: {query}")
response = {
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({
"message": "Lambda function executed successfully",
"method": http_method,
"path": path,
"timestamp": "2026-06-28T00:00:00Z"
})
}
return response
# Test locally
test_event = {
"httpMethod": "GET",
"path": "/api/health",
"queryStringParameters": {"version": "v2"}
}
print(json.dumps(lambda_handler(test_event, None), indent=2))
Expected output:
Processing GET /api/health
Query params: {'version': 'v2'}
{
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": "{\"message\": \"Lambda function executed successfully\", \"method\": \"GET\", \"path\": \"/api/health\", \"timestamp\": \"2026-06-28T00:00:00Z\"}"
}
Lambda Execution Context
The execution context provides runtime information and reused resources for warm invocations. Use it for caching database connections and HTTP clients.
# lambda_context.py
# Using the Lambda execution context
import boto3
import json
# Initialized outside handler = reused across warm invocations
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table("my-table")
def lambda_handler(event, context):
"""Handler that reuses database connection."""
request_id = context.aws_request_id
remaining = context.get_remaining_time_in_millis()
print(f"Request ID: {request_id}")
print(f"Timeout remaining: {remaining}ms")
print(f"Function name: {context.function_name}")
print(f"Memory limit: {context.memory_limit_in_mb}MB")
# Use cached connection
response = table.get_item(Key={"id": event.get("id")})
return {
"statusCode": 200,
"body": json.dumps(response.get("Item", {}))
}
Lambda Permissions with IAM
Every Lambda function needs an IAM role with permissions to access the AWS services it uses. The principle of Least Privilege means granting only the specific actions needed.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
Lambda Configuration Options
Configure memory from 128MB to 10GB with proportional CPU allocation. Timeout from 1 second to 15 minutes. Reserved concurrency guarantees capacity. Provisioned concurrency eliminates cold starts.
# lambda_config.py
# Understanding Lambda configuration
def calculate_memory_cost(memory_mb, duration_ms):
"""Lambda cost depends on memory and duration."""
gb_seconds = (duration_ms / 1000) * (memory_mb / 1024)
cost = gb_seconds * 0.0000166667
return cost
configs = [
(128, 100),
(512, 100),
(1024, 100),
(3008, 100),
]
for memory, duration in configs:
cost = calculate_memory_cost(memory, duration)
print(f"Memory: {memory}MB, Duration: {duration}ms, Cost: ${cost:.6f}")
Expected output:
Memory: 128MB, Duration: 100ms, Cost: $0.0000002
Memory: 512MB, Duration: 100ms, Cost: $0.0000008
Memory: 1024MB, Duration: 100ms, Cost: $0.0000016
Memory: 3008MB, Duration: 100ms, Cost: $0.0000048
Common Mistakes
Not setting a dead-letter queue: Failed invocations are lost. Configure DLQ for SQS or SNS to capture and analyze failures.
Over-provisioning memory: Higher memory costs more and may not improve performance for I/O-bound functions. Test with different configurations.
Ignoring the /tmp directory limit: Lambda provides 512MB to 10GB of ephemeral storage in /tmp. This is not persistent across invocations.
Exposing environment variables with secrets: Environment variables are visible in the Lambda console. Use AWS Secrets Manager or Parameter Store for sensitive values.
Not using alias versions for deployments: Lambda aliases let you point to specific function versions, enabling canary deployments and rollbacks.
Practice Questions
What is the Lambda execution context? The context object provides runtime information, request ID, timeout, function name, and identity information for the invocation.
How does Lambda scale with traffic? Lambda creates new execution environments per concurrent request, scaling up to account-level concurrency limits.
What is the maximum memory for a Lambda function? 10GB as of 2026. Memory also determines CPU allocation proportionally.
How do you handle secrets in Lambda? Use AWS Secrets Manager or SSM Parameter Store, not environment variables. Retrieve secrets at initialization.
Challenge: Create a Lambda function triggered by DynamoDB Streams that processes new user signups, enriches the data with geolocation from IP address, and stores the result in another DynamoDB table.
FAQ
Mini Project
Create a Lambda function that processes incoming Webhook events from Stripe, verifies the signature, handles checkout.session.completed events by looking up the customer and storing the subscription in DynamoDB.
import json
import hashlib
import hmac
def lambda_handler(event, context):
headers = event.get("headers", {})
body = event.get("body", "{}")
signature = headers.get("stripe-signature", "")
secret = "whsec_your_webhook_secret"
expected = hmac.new(secret.encode(), body.encode(), hashlib.sha256).hexdigest()
if signature != expected:
return {"statusCode": 403, "body": json.dumps({"error": "Invalid signature"})}
payload = json.loads(body)
event_type = payload.get("type", "")
if event_type == "checkout.session.completed":
session = payload["data"]["object"]
customer_id = session.get("customer")
subscription_id = session.get("subscription")
print(f"New subscription: {subscription_id} for customer {customer_id}")
return {"statusCode": 200, "body": json.dumps({"received": True})}
What's Next
Next: Lambda Functions for detailed patterns and best practices.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro