This project implements a serverless image processing pipeline using AWS Lambda, Amazon S3, and DynamoDB. When an image is uploaded to the source S3 bucket, the Lambda function automatically resizes it and stores the output in a destination bucket. Metadata such as file name, size, and format are also recorded in DynamoDB.
Create two S3 buckets — one for uploading original images and one for storing resized versions.
aws s3 mb s3://source-bucket-name aws s3 mb s3://destination-bucket-name
Create a DynamoDB table named ImageMetadata to store image metadata.
Commands:
aws dynamodb create-table
--table-name ImageMetadata
--attribute-definitions AttributeName=ImageID,AttributeType=S
--key-schema AttributeName=ImageID,KeyType=HASH
--billing-mode PAY_PER_REQUEST
Below is the Lambda function used to resize images and store metadata in DynamoDB.
Code (Python):
import boto3 import os import uuid from PIL import Image from io import BytesIO
s3 = boto3.client('s3') dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('ImageMetadata')
def lambda_handler(event, context): source_bucket = event['Records'][0]['s3']['bucket']['name'] key = event['Records'][0]['s3']['object']['key'] destination_bucket = os.environ['DEST_BUCKET']
image_obj = s3.get_object(Bucket=source_bucket, Key=key)
image_data = image_obj['Body'].read()
image = Image.open(BytesIO(image_data))
image = image.resize((200, 200))
buffer = BytesIO()
image.save(buffer, 'PNG')
buffer.seek(0)
resized_key = f"resized-{key}"
s3.put_object(Bucket=destination_bucket, Key=resized_key, Body=buffer, ContentType='image/png')
table.put_item(Item={
'ImageID': str(uuid.uuid4()),
'OriginalFile': key,
'ResizedFile': resized_key,
'Bucket': destination_bucket
})
return {'status': 'success', 'resized_image': resized_key}
Attach an AWS precompiled Pillow layer compatible with your Lambda runtime.
Example ARN (Python 3.11, us-east-2): arn:aws:lambda:us-east-2:770693421928:layer:Klayers-p311-Pillow:10
Download layers: Klayers GitHub
Command:
aws lambda update-function-configuration
--function-name ImageResizer
--environment "Variables={DEST_BUCKET=}"
Attach permissions allowing Lambda to access S3 and DynamoDB.
AmazonS3FullAccess
AmazonDynamoDBFullAccess
Least-privilege IAM policy example:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:GetObject", "s3:PutObject"], "Resource": ["arn:aws:s3:::source-bucket-name/", "arn:aws:s3:::destination-bucket-name/"] }, { "Effect": "Allow", "Action": ["dynamodb:PutItem"], "Resource": "arn:aws:dynamodb:region:account-id:table/ImageMetadata" } ] }
Upload an image to the source bucket.
Wait for Lambda to trigger automatically.
Check the destination bucket for the resized image.
Verify metadata in DynamoDB.
-
Runtime.ImportModuleError
→ Use a precompiled AWS Pillow layer matching your runtime. -
Runtime.OutOfMemory
→ Increase Lambda memory allocation to 512–1024 MB. -
Images not appearing in destination bucket
→ Recheck S3 event notifications and Lambda IAM role permissions. -
No logs visible
→ Enable CloudWatch Logs in Lambda configuration.
AWS Lambda – Very low (charged by execution time)
Amazon S3 – Low (storage + requests)
Amazon DynamoDB – Low (free tier sufficient)
CloudWatch Logs – Minimal
Create S3 buckets and DynamoDB table
Create Lambda function, add code
Add environment variable DEST_BUCKET=
Attach IAM role
Add Pillow layer
Configure S3 event trigger
Test by uploading an image
zip function.zip lambda_function.py
aws lambda create-function
--function-name ImageResizer
--runtime python3.9
--role arn:aws:iam:::role/
--handler lambda_function.lambda_handler
--zip-file fileb://function.zip
aws lambda update-function-configuration
--function-name ImageResizer
--environment "Variables={DEST_BUCKET=}"
aws lambda update-function-configuration
--function-name ImageResizer
--layers arn:aws:lambda:us-east-2:770693421928:layer:Klayers-p311-Pillow:10
aws s3api put-bucket-notification-configuration
--bucket
--notification-configuration file://notification.json
This serverless pipeline automates image processing and metadata storage without provisioning servers. It combines S3, Lambda, DynamoDB, and CloudWatch for scalable, event-driven, and cost-efficient solutions.
-
Generate multiple image sizes
-
Integrate API Gateway to trigger resizing via HTTP
-
Add SNS notifications
-
Enable CloudFront caching
-
Add Rekognition integration
-
Use AWS Step Functions
-
Add error handling & logging
-
Deploy using AWS SAM or CDK









