What is Lambda Handler: Python Function Basics
A Lambda handler is the Python function that AWS Lambda invokes when triggered. The handler receives two arguments—event and context—and must return a value that Lambda serializes to JSON and returns to the caller. Understanding handler mechanics is essential for building robust serverless applications.
What is a Lambda Handler?
A Lambda handler is a Python function designated as the entry point for a Lambda function execution. When you create a function in the AWS Lambda Console or via code, you specify the handler in the format filename.function_name. For example, if your code file is index.py and the function is my_handler, the handler is index.my_handler.
The handler signature is always:
def handler_name(event, context):
# Process event
return response
Lambda automatically calls this function whenever the function is invoked—either through the console, AWS CLI, API Gateway, or any other trigger. The handler is responsible for processing the input (event), performing business logic, and returning a response.
Understanding the Event Object
The event dictionary contains data from the triggering service. Its structure depends on the source. Here are common patterns:
API Gateway HTTP Request:
def lambda_handler(event, context):
# event structure:
# {
# "httpMethod": "GET",
# "path": "/users/123",
# "queryStringParameters": {"format": "json"},
# "headers": {"Content-Type": "application/json"},
# "body": None,
# "isBase64Encoded": false
# }
method = event.get('httpMethod') # 'GET'
path = event.get('path') # '/users/123'
query = event.get('queryStringParameters', {})
return {
'statusCode': 200,
'body': f'Received {method} request to {path}'
}
S3 Bucket Event:
def lambda_handler(event, context):
# event structure:
# {
# "Records": [
# {
# "s3": {
# "bucket": {"name": "my-bucket"},
# "object": {"key": "uploads/photo.jpg", "size": 5000}
# }
# }
# ]
# }
for record in event.get('Records', []):
bucket = record['s3']['bucket']['name']
key = record['s3']['object']['key']
size = record['s3']['object']['size']
print(f'Processed {key} from {bucket} ({size} bytes)')
return {'statusCode': 200, 'message': 'Processing complete'}
The event structure is defined by the triggering service and is always provided as a Python dictionary. AWS documentation specifies the exact schema for each service.
Understanding the Context Object
The context object is a Lambda runtime object that provides metadata about the current invocation. Common properties include:
function_name: The name of the Lambda functionfunction_version: The version of the function (e.g.,$LATEST)invoked_function_arn: The full ARN of the functionmemory_limit_in_mb: The memory allocated (as a string, e.g.,'128')aws_request_id: Unique request identifier for CloudWatch tracinglog_group_name: CloudWatch Logs group for this functionlog_stream_name: CloudWatch Logs stream for this invocationget_remaining_time_in_millis(): Method returning milliseconds until timeout
Use context for logging, tracing, and detecting timeouts:
import json
import time
def lambda_handler(event, context):
print(f'Function: {context.function_name}')
print(f'Request ID: {context.aws_request_id}')
print(f'Memory: {context.memory_limit_in_mb} MB')
# Simulate work
time.sleep(1)
remaining_ms = context.get_remaining_time_in_millis()
print(f'Time remaining: {remaining_ms} ms')
if remaining_ms < 5000:
raise TimeoutError('Insufficient time to complete')
return {
'statusCode': 200,
'requestId': context.aws_request_id,
'body': json.dumps({'status': 'success'})
}
Handler Return Values and Response Format
The handler's return value is serialized to JSON and returned to the caller. For API Gateway triggers, return a specific structure:
def lambda_handler(event, context):
try:
user_id = event['pathParameters']['id']
# Fetch user from database (example)
user = {'id': user_id, 'name': 'Alice', 'email': '[email protected]'}
return {
'statusCode': 200,
'headers': {'Content-Type': 'application/json'},
'body': json.dumps(user)
}
except KeyError:
return {
'statusCode': 400,
'body': json.dumps({'error': 'Missing id parameter'})
}
except Exception as e:
return {
'statusCode': 500,
'body': json.dumps({'error': str(e)})
}
For non-HTTP triggers (S3, SQS, DynamoDB), return any JSON-serializable value:
def lambda_handler(event, context):
# Process batch of SQS messages
results = []
for record in event['Records']:
message_id = record['messageId']
body = record['body']
# Process and collect result
results.append({'id': message_id, 'processed': True})
return {'statusCode': 200, 'processed_count': len(results)}
Error Handling and Exceptions
When a handler raises an exception, Lambda catches it, formats the error, and returns it to the caller. Log the exception for debugging:
import json
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
try:
# Validate input
if 'required_field' not in event:
raise ValueError('required_field is missing')
# Process
result = do_work(event['required_field'])
return {
'statusCode': 200,
'body': json.dumps({'result': result})
}
except ValueError as e:
logger.error(f'Validation error: {str(e)}')
return {
'statusCode': 400,
'body': json.dumps({'error': 'Invalid input'})
}
except Exception as e:
logger.exception('Unexpected error')
return {
'statusCode': 500,
'body': json.dumps({'error': 'Internal server error'})
}
def do_work(value):
return f'Processed: {value}'
Structured logging (with correlation IDs from context.aws_request_id) enables tracking requests across logs and related services.
Choosing a Handler Name
The handler name convention is flexible but matters for clarity:
lambda_handler— Default name, works for most caseshandler— Short, common conventionapi_handler,s3_handler— Descriptive names for multi-trigger setups
When defining the handler in AWS, use the format filename.function_name. If your code is in app.py and the function is handle_request, the handler value in Lambda Console is app.handle_request.
For a single-file function:
# app.py
def lambda_handler(event, context):
return {'statusCode': 200, 'body': 'OK'}
In the Lambda Console, set Handler to app.lambda_handler.
Passing Custom Data via Event
For testing and custom workflows, pass arbitrary event data:
# aws lambda invoke --function-name my-func --payload '{"user": "bob", "action": "login"}' output.json
def lambda_handler(event, context):
user = event.get('user', 'unknown')
action = event.get('action', 'unknown')
print(f'User {user} performed {action}')
return {'statusCode': 200, 'user': user}
The --payload argument accepts any JSON; AWS automatically decodes it into the event dictionary.
Key Takeaways
- A Lambda handler is a Python function that receives
eventandcontext, processes data, and returns a JSON-serializable response. - The
eventdictionary structure depends on the triggering service; API Gateway, S3, SQS, and DynamoDB each have defined schemas. - The
contextobject provides metadata: function name, request ID, remaining time, and CloudWatch references for logging and tracing. - Return values are serialized to JSON; for HTTP APIs, use the standard structure with
statusCode,headers, andbody. - Always implement error handling with try-except blocks and log exceptions for production debugging.
- Handler names are customizable; the format is
filename.function_nameas specified in Lambda configuration.
Frequently Asked Questions
Can I have multiple handlers in one function?
Yes, but only one is invoked per execution. You can define multiple functions in the same file and change the Handler setting in the Lambda Console to call different ones. For example, app.api_handler vs. app.batch_handler. However, for clarity, a single handler per function is standard.
What happens if my handler doesn't return anything?
If your handler returns None (or no explicit return), Lambda returns null. For API Gateway, this results in a null body, which may be invalid HTTP. Always return a proper response dictionary for API-driven functions.
How do I access environment variables in a handler?
Use import os; os.environ['KEY_NAME']. Define variables in the Lambda Console under Configuration → Environment variables. This pattern is safer than hardcoding secrets; combine with AWS Secrets Manager for sensitive data.
Can I change the handler after deployment?
Yes, in the Lambda Console under Configuration → General, or via aws lambda update-function-configuration --function-name my-func --handler new_file.new_handler. The change applies immediately to new invocations.
What's the maximum size of an event or response?
Event payloads are limited by the triggering service (API Gateway: 10 MB, SQS: 256 KB per message). Response bodies are limited similarly. Always compress large payloads or store them in S3 and pass a reference.
Further Reading
- AWS Lambda Handler Interface — Official handler specification and context object reference
- API Gateway Lambda Proxy Integration — HTTP response format specification
- Lambda Event Schemas — Detailed structures for all trigger types
- Python Logging Best Practices — Structured logging for Lambda environments