AWS Lambda runs your code without managing servers โ you pay only for execution time, and it scales automatically from zero to thousands of concurrent requests. This guide deploys a Python API to Lambda with API Gateway from scratch.
๐ Table of Contents
When to Use Lambda
- Good fit: APIs with variable traffic, scheduled jobs, event processing, webhooks, lightweight microservices
- Poor fit: Long-running processes (15-min limit), consistently high traffic (cheaper on always-on servers), apps needing persistent connections (WebSockets need API Gateway v2)
Method 1: Simple Lambda Function (Console)
# handler.py โ the entry point
import json
def lambda_handler(event, context):
# event contains the request data
name = event.get('queryStringParameters', {}).get('name', 'World')
return {
'statusCode': 200,
'headers': {'Content-Type': 'application/json'},
'body': json.dumps({'message': f'Hello, {name}!'})
}
Packaging Dependencies
Lambda needs your dependencies bundled. For packages like requests:
# Install dependencies into a package directory
mkdir package
pip install requests -t package/
# Add your handler
cp handler.py package/
# Zip it
cd package
zip -r ../deployment.zip .
cd ..
# Upload deployment.zip to Lambda
Method 2: Serverless Framework (Recommended)
npm install -g serverless
serverless create --template aws-python3 --path my-api
cd my-api
npm install serverless-python-requirements
# serverless.yml
service: my-api
provider:
name: aws
runtime: python3.12
region: us-east-1
environment:
STAGE: ${sls:stage}
DB_URL: ${env:DB_URL}
functions:
api:
handler: handler.lambda_handler
events:
- httpApi:
path: /hello
method: get
- httpApi:
path: /users/{id}
method: get
timeout: 29
memorySize: 256
plugins:
- serverless-python-requirements
custom:
pythonRequirements:
dockerizePip: true # builds native deps in a Lambda-compatible container
# requirements.txt
requests==2.32.0
boto3==1.34.0
# Deploy
serverless deploy
# Output gives your API Gateway URL:
# endpoint: GET - https://abc123.execute-api.us-east-1.amazonaws.com/hello
Handling API Gateway Events
import json
def lambda_handler(event, context):
# httpApi (v2) event structure
method = event['requestContext']['http']['method']
path = event['requestContext']['http']['path']
params = event.get('pathParameters') or {}
query = event.get('queryStringParameters') or {}
body = json.loads(event['body']) if event.get('body') else {}
if path.startswith('/users/'):
user_id = params.get('id')
return respond(200, {'userId': user_id})
return respond(404, {'error': 'Not found'})
def respond(status, data):
return {
'statusCode': status,
'headers': {'Content-Type': 'application/json'},
'body': json.dumps(data)
}
Managing Cold Starts
Lambda “cold starts” when a new container spins up (first request or after idle). Minimize impact:
- Keep the package small: Fewer dependencies = faster cold start. Only import what you use.
- Initialize outside the handler: Database clients and config load once per container, reused across warm invocations
- Use Provisioned Concurrency for latency-critical endpoints (keeps containers warm, costs extra)
- Increase memory: More memory also means more CPU, reducing init time
# โ
Initialize clients OUTSIDE the handler (reused across invocations)
import boto3
dynamodb = boto3.resource('dynamodb') # created once per container
table = dynamodb.Table('users')
def lambda_handler(event, context):
# table is already initialized โ no per-request setup cost
return table.get_item(Key={'id': '1'})
Environment Variables and Secrets
# Non-sensitive config: environment variables (serverless.yml)
environment:
LOG_LEVEL: info
# Sensitive secrets: use AWS Secrets Manager or SSM Parameter Store
import boto3
ssm = boto3.client('ssm')
def get_secret(name):
resp = ssm.get_parameter(Name=name, WithDecryption=True)
return resp['Parameter']['Value']
DB_PASSWORD = get_secret('/myapp/db_password') # loaded once per container
Frequently Asked Questions
Q: How much does Lambda cost?
A: The free tier includes 1M requests and 400,000 GB-seconds monthly. Beyond that, you pay per request and per GB-second of execution. For variable-traffic APIs, it’s often far cheaper than an always-on server.
Q: What’s the maximum execution time?
A: 15 minutes. For longer tasks, use AWS Step Functions to orchestrate multiple Lambdas, or move to ECS/Fargate for long-running processes.
Q: How do I connect Lambda to a database?
A: For serverless-friendly databases, use DynamoDB or Aurora Serverless. For traditional Postgres/MySQL, use RDS Proxy to manage connection pooling (Lambda’s scaling can exhaust DB connections otherwise).
Q: Can I run a full web framework on Lambda?
A: Yes โ use Mangum (for FastAPI/Starlette) or Zappa (for Flask/Django) to adapt WSGI/ASGI apps to Lambda. Good for migrating existing apps, though native handlers are lighter.
Q: How do I debug Lambda locally?
A: Use serverless invoke local or AWS SAM CLI’s sam local start-api to run functions locally. CloudWatch Logs capture all production execution logs.
Conclusion
AWS Lambda lets you deploy Python APIs that scale automatically and cost nothing when idle. The Serverless Framework approach โ serverless.yml plus serverless-python-requirements โ handles packaging, API Gateway, and deployment in one command. Initialize clients outside the handler to reduce cold-start cost, use SSM/Secrets Manager for credentials, and reach for Provisioned Concurrency only when latency truly matters. It’s an excellent fit for variable-traffic APIs and event-driven workloads.
๐ You might also like
๐ Share this article




โ๏ธ Leave a Comment