Unleash the power of<serverless>
with Powertools
for AWS

Powertools for AWS is a developer toolkit to implement Serverless best practices and increase developer velocity
Voices of Success
Hear what our customers have to say

Capital One has widely-adopted Powertools for AWS for projects across the enterprise. Powertools allows us to implement serverless best practices by leveraging the boundless resources provided by the global open source community. Whether it’s an organization’s first serverless project or development of a new serverless platform, Powertools for AWS can help companies improve developer productivity and easily implement common best practice tasks.
Daniel Furman
Distinguished Engineer at Capital One

Diving into the world of serverless? Powertools for AWS Lambda is a game-changer! It's like the Swiss Army knife for our serverless journey. Honestly, I can't imagine writing serverless without it anymore.
Ran Isenberg
Principal Software Architect at CyberArk
<turbocharge>
your code
Powertools takes care of the heavy lifting, ensuring that your serverless applications adhere to industry-leading best practices. Say goodbye to tedious manual configuration and hello to automated optimization. Powertools for AWS effortlessly implements key serverless practices, including optimized resource allocation, efficient event-driven architecture, and streamlined scalability.
1250
Total lines of code
0%
Lines reduced
1import json
2import logging
3import os
4import boto3
5from aws_xray_sdk.core import xray_recorder
6from aws_xray_sdk.core import patch
7
8# Configure the logger
9logging.basicConfig(format='%(asctime)s - %(name)s -
10%(levelname)s - %(message)s')
11logger = logging.getLogger()
12logger.setLevel(logging.INFO)
13
14# Configure AWS X-Ray
15patch(['boto3'])
16xray_recorder.configure(service='my-lambda-function')
17xray_recorder.configure(context_missing='LOG_ERROR')
18xray_recorder.configure(streaming_threshold=0)
19
20# Configure CloudWatch
21cloudwatch = boto3.client('cloudwatch')
22
23# Set cold start to true
24is_cold_start = True
25
26# Create a function to publish CloudWatch custom metrics
27def publish_custom_metric(value, metric_name):
28 cloudwatch.put_metric_data(
29 Namespace='WebsiteExample',
30 MetricData=[
31 {
32 'MetricName': metric_name,
33 'Value': value,
34 'Unit': 'Count'
35 }
36 ]
37 )
38
39def is_valid_payload(payload):
40 # Check if the payload resembles an AWS API Gateway event
41 return all(key in payload for key in ('httpMethod',
42 'path', 'queryStringParameters'))
43
44def lambda_handler(event, context):
45
46 # Initialize a trace segment
47 with xray_recorder.in_subsegment("## Lambda Handler ##")
48 as subsegment:
49 # Check if the function is a cold start and create a
50 metric
51 global is_cold_start
52 if not is_cold_start:
53 logger.info("Cold start detected.
54 Initializing...")
55 publish_custom_metric(is_cold_start, "ColdStart")
56 is_cold_start = False
57
58 subsegment.put_annotation("ColdStart", "True")
59
60 # Check if the event resembles an AWS API Gateway
61 event
62 if is_valid_payload(event):
63 # Check the HTTP method of the request
64 http_method = event['httpMethod']
65
66 # Default response content
67 response = {
68 "statusCode": 200,
69 "headers": {
70 "Content-Type": "application/json"
71 },
72 "body": ""
73 }
74
75 # Retrieve the "id_todo" variable from the query
76 parameters in the GET method
77 if http_method == "GET" and event['path'] == "/
78 example":
79 id_todo = event['queryStringParameters']
80 ['id_todo']
81 response["body"] = json.dumps({"message":
82 f"This is the GET route /example, id_todo:
83 {id_todo}"})
84 log_context = {
85 "http_method": http_method,
86 "path": event['path'],
87 "id_todo": id_todo
88 }
89 logger.info(json.dumps(log_context))
90 # Publish a custom metric for the GET request
91 publish_custom_metric(1, "GETRequestCount")
92 subsegment.put_metadata("response",
93 log_context)
94 # Receive a payload with "id_todo" and
95 "name_todo" in the POST method
96 elif http_method == "POST" and event['path'] ==
97 "/example":
98 request_body = json.loads(event['body'])
99 id_todo = request_body.get('id_todo')
100 name_todo = request_body.get('name_todo')
101 log_context = {
102 "http_method": http_method,
103 "path": event['path'],
104 "request_data": request_body
105 }
106 # Verify if the payload fields are filled
107 if id_todo and name_todo:
108 response["body"] = json.dumps({"message":
109 f"This is the POST route /example,
110 id_todo: {id_todo}, name_todo:
111 {name_todo}"})
112 logger.info(json.dumps(log_context))
113 # Publish a custom metric for the POST
114 request
115 publish_custom_metric(1,
116 "POSTRequestCount")
117 subsegment.put_metadata("response",
118 log_context)
119 else:
120 response["statusCode"] = 400 # Bad
121 Request
122 response["body"] = json.dumps({"message":
123 "Missing 'id_todo' or 'name_todo' in the
124 payload"})
125 logger.warning(json.dumps(log_context))
126 else:
127 # Handle other methods or paths, if needed
128 response["statusCode"] = 404
129 response["body"] = json.dumps({"message":
130 "Route not found"})
131 log_context = {
132 "http_method": http_method,
133 "path": event['path'],
134 "message": "Route not found"
135 }
136 logger.warning(json.dumps(log_context))
137 else:
138 # Handle cases where the payload doesn't resemble
139 an AWS API Gateway event
140 response = {
141 "statusCode": 400,
142 "headers": {
143 "Content-Type": "application/json"
144 },
145 "body": json.dumps({"message": "Invalid
146 payload format"})
147 }
148 logger.warning("Invalid payload format")
149
150 return response
<install>
Powertools for AWS
Python
TypeScript
Java
.NET
Lambda Layer (x86_64)
arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:78
Lambda Layer (arm64)
arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:78
Pip
pip install "aws-lambda-powertools"

Open source
freedom
Harness the Power of our MIT-Licensed Solution
Get going with
Powertools
for AWS
<it’s free>
Powertools for AWS
© 2025, Amazon Web Services, Inc. or its affiliates. All rights reserved.