Automatically resize uploaded images using AWS SAM, Lambda, S3, API Gateway, and CloudFront.
User Upload → S3 Input Bucket → Lambda Function → S3 Output Bucket → CloudFront
- Automatic Resizing: Creates 3 sizes (thumbnail: 150x150, medium: 500x500, large: 1200x1200)
- Multiple Formats: Supports JPEG, PNG, and other PIL-compatible formats
- Global CDN: Optional CloudFront distribution for fast image delivery
- REST API: Optional upload endpoint via API Gateway
- SAM Framework: Simplified serverless deployment
- Cross-Platform: Works on any OS without Docker
-
Install SAM CLI:
# macOS brew install aws-sam-cli # Or follow: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html
-
Install AWS CLI:
# macOS brew install awscli -
Configure AWS Credentials:
aws configure
-
Deploy Infrastructure:
chmod +x *.sh ./deploy.shThe script will prompt for:
- Project name (default: serverless-image-resizer)
- AWS region (default: us-east-1)
- CloudFront CDN (y/n)
- API Gateway (y/n)
-
Note the outputs after deployment for bucket names and URLs.
-
Test the system:
# Upload a test image aws s3 cp sample-images/your-image.jpg s3://YOUR-INPUT-BUCKET/ # Check results ./check-results.sh
# Get your input bucket name from deployment output
INPUT_BUCKET="your-input-bucket-name"
# Upload an image
aws s3 cp sample-images/your-image.jpg s3://$INPUT_BUCKET/
# Check resized images in output bucket
OUTPUT_BUCKET="your-output-bucket-name"
aws s3 ls s3://$OUTPUT_BUCKET/resized/ --recursive# Get API endpoint from deployment output
API_ENDPOINT="your-api-gateway-url"
# Upload image via API
curl -X POST "$API_ENDPOINT?key=test-image.jpg" \
--data-binary @sample-images/your-image.jpg \
--header "Content-Type: image/jpeg"- Go to S3 in AWS Console
- Find your input bucket
- Upload images directly through the web interface
# Replace with your output bucket name
OUTPUT_BUCKET="your-output-bucket-name"
# Access resized images
https://s3.amazonaws.com/$OUTPUT_BUCKET/resized/thumbnail/your-image.jpg
https://s3.amazonaws.com/$OUTPUT_BUCKET/resized/medium/your-image.jpg
https://s3.amazonaws.com/$OUTPUT_BUCKET/resized/large/your-image.jpg# Replace with your CloudFront domain from deployment output
CLOUDFRONT_URL="your-cloudfront-domain"
# Access via CDN (faster, cached globally)
https://$CLOUDFRONT_URL/resized/thumbnail/your-image.jpg
https://$CLOUDFRONT_URL/resized/medium/your-image.jpg
https://$CLOUDFRONT_URL/resized/large/your-image.jpg├── template.yaml # SAM template
├── src/
│ └── lambda_function.py # Lambda function code
├── sample-images/ # Test images directory
├── deploy.sh # Full deployment script
├── update-lambda.sh # Quick Lambda code updates
├── check-results.sh # Check resized images
├── cleanup.sh # Cleanup script
└── README.md # This file
- Add test images to
sample-images/directory - Upload using any method above
- Check results:
./check-results.sh
- Verify sizes: thumbnail (150x150), medium (500x500), large (1200x1200)
After uploading images, use the results checker:
# Check if resized images were created
./check-results.shThis will:
- List all resized images in output bucket
- Show direct S3 access URLs
- Confirm processing worked correctly
Modify src/lambda_function.py to customize:
- Output sizes
- Image quality
- Supported formats
- Processing logic
For code-only changes to src/lambda_function.py:
# Fast update (no infrastructure changes)
./update-lambda.shUse this instead of full deployment when:
- ✅ Modifying Lambda code only
- ✅ Testing function logic
- ✅ Avoiding SAM build time
For infrastructure changes, use ./deploy.sh
- CloudWatch Logs: Check Lambda function logs
- S3 Events: Monitor bucket notifications
- Lambda Metrics: View function performance
chmod +x cleanup.sh
./cleanup.shThis will:
- Empty S3 buckets
- Delete CloudFormation stack
- Remove all AWS resources
- Clean up local files
- Lambda: ~$0.20 per 1M requests
- S3: ~$0.023 per GB storage
- CloudFront: ~$0.085 per GB transfer (if enabled)
- API Gateway: ~$3.50 per 1M requests (if enabled)
-
"No module named PIL": Layer not installed correctly
- Re-run
./deploy.sh
- Re-run
-
"Access Denied": Check AWS credentials
- Run
aws configure
- Run
-
"Stack already exists": Use cleanup first
- Run
./cleanup.shthen./deploy.sh
- Run
# View Lambda logs
aws logs describe-log-groups --log-group-name-prefix /aws/lambda/serverless-image-resizer
# View specific log stream
aws logs get-log-events --log-group-name /aws/lambda/your-function-name --log-stream-name LATEST- Initial deployment:
./deploy.sh - Test uploads: Use AWS CLI, API Gateway, or Console
- Check results:
./check-results.sh - Modify Lambda code: Edit
src/lambda_function.py - Quick update:
./update-lambda.sh - Test again: Upload and check results
- Infrastructure changes:
./deploy.sh - Cleanup when done:
./cleanup.sh
- Social Media: Profile picture resizing
- E-commerce: Product image thumbnails
- Portfolios: Performance optimization
- Content Management: Automatic image processing
- Mobile Apps: Multiple resolution support