The Serverless Image Resizer is a cloud-native application that enables users to upload images and automatically resize them to predefined dimensions optimized for various social media platforms. Built on AWS serverless architecture, it provides a simple web interface for image management while handling the complex image processing behind the scenes.
The application offers a comprehensive set of features including:
- π€ Secure image upload using pre-signed URLs
- βοΈ One-click image resizing with predefined dimensions for popular social media platforms (Instagram, Facebook, X, LinkedIn, YouTube)
- π€ Automatic image processing using AWS Lambda
- π Modal-based Original Image Preview
- π₯ Download Resized Images
- β Delete Images via API Gateway
- π Timestamps and File Size Display
- π CloudFront CDN integration for fast global content delivery
- π CORS-enabled API for secure cross-origin requests
- πΌοΈ Responsive web interface with image preview and management capabilities
All of the above happens without managing any server - AWS services handle the scaling automatically.
Here, I'll walk you through how I built the solution using AWS services, including Lambda, S3, CloudFront, and API Gateway, all deployed with Terraform.
In order to keep the lenght of this article moderate, I kept the project configuration out of this post. Please find them in my Github Page.
Prerequisites
- AWS Account with appropriate permissions
- Node.js 18.x or later
- Terraform 1.0 or later
- AWS CLI configured with appropriate credentials
- Domain name registered in Route 53
- SSL certificate in AWS Certificate Manager
Project Structure
.
βββ frontend/ # Web interface files
β βββ app.js # Frontend JavaScript application logic
β βββ index.html # Main HTML interface
βββ lambda/ # AWS Lambda functions
β βββ delete/ # Image deletion function
β βββ list/ # Image listing function
β βββ presign/ # Pre-signed URL generation
β βββ resize/ # Image resizing function
βββ terraform/ # Infrastructure as Code
βββ api_gateway.tf # API Gateway configuration
βββ cloudfront.tf # CDN distribution setup
βββ iam+s3.tf # IAM roles and S3 bucket configuration
βββ lambda.tf # Lambda functions configuration
βββ main.tf # Main Terraform configuration
βββ outputs.tf # Output variables
βββ route53.tf # DNS configuration
βββ variables.tf # Input variables
π§± Architecture Overview
- Frontend: HTML, Bootstrap, jQuery, and Handlebars.js
- Storage: Amazon S3 (Original and Resized Buckets)
-
Compute: AWS Lambda for:
- Generating pre-signed URLs
- Resizing images using Sharp
- Listing images with metadata
- Deleting images
Routing: API Gateway
Delivery: CloudFront (backed by S3 for secure and fast access)
Security: IAM roles and bucket policies for fine-grained access control
-
Infrastructure Management:
- Defined via Terraform
- Deployed through GitHub Actions
π§© The Development Process
1. Bucket Setup
I created three S3 buckets:
-
original-images-bucket-foz
- Stores original image uploads -
resized-images-bucket-foz
- Stores Resized images -
Image-resizer.fozdigitalz.com
- Hosts the front end
With appropriate IAM roles and bucket policies to support Lambda functions and CloudFront delivery. Users can only access the original and resized buckets via CloudFront.
2. Frontend UI
- Used Bootstrap for responsive layout.
- Handlebars templates for dynamic image card rendering.
- Modal for viewing original images.
- Buttons to Load, Download, View, and Delete images.
Users can click "View Original" to open a Bootstrap modal. This dynamically loads the full-size original image via CloudFront.
I defined grouped resize sizes dynamically in JavaScript. Users can select any of these sizes from the front end.
const resizeOptionsGrouped = [
{
groupName: "Social Media Sizes",
options: [
{ platform: "Instagram πΈ", label: "Post", size: "1080x1080" },
{ platform: "Facebook π", label: "Shared Image", size: "1200x630" },
{ platform: "Twitter/X π¦", label: "Summary", size: "1200x675" },
{ platform: "LinkedIn πΌ", label: "Link Image", size: "1200x627" },
{ platform: "YouTube βΆοΈ", label: "Thumbnail", size: "1280x720" }
]
},
{
groupName: "Standard Sizes",
options: [
{ platform: "Thumbnail ποΈ", label: "", size: "150x150" },
{ platform: "Medium", label: "", size: "640x480" },
{ platform: "Large", label: "", size: "800x600" },
{ platform: "Full HD", label: "", size: "1920x1080" }
]
}
];
3. Backend: Serverless Power with API Gateway & Lambda
The backend orchestrates image processing through a seamless AWS serverless stack:
API Gateway: The Traffic Controller
- Serves as the single entry point for all frontend requests
- Configured with CORS to securely allow requests only from your frontend domain
- Routes requests to specific Lambda functions based on path/verb:
# Example route definition for Presigm Lambda in Terraform
resource "aws_apigatewayv2_route" "presign_route" {
api_id = aws_apigatewayv2_api.image_api.id
route_key = "GET /presign" # Routes to presign Lambda
target = "integrations/${aws_apigatewayv2_integration.presign_integration.id}"
}
Lambda Functions: Specialized Workers
Four dedicated functions handle distinct tasks:
I. Presign Lambda
- Generates secure S3 upload URLs with metadata
const signedUrl = await getSignedUrl(s3, putCommand, { expiresIn: 300 });
II. Resize Lambda
- Triggered by S3 upload events, uses
sharp
to resize image withfit: 'inside'
andkernel: 'lanczos3'
for quality.
await sharp(imageBuffer).resize(width, height).toBuffer();
III. List Lambda
- Returns all uploaded images for the UI gallery with file name timestamp, and size.
const data = await s3.send(new ListObjectsV2Command({ Bucket: BUCKET_NAME }));
IV. Delete Lambda
- Removes images from S3 when requested
await s3.send(new DeleteObjectCommand({ Bucket: BUCKET_NAME, Key: fileName }));
4. CloudFront Distribution
I used Origin Access Control (OAC) to ensure only CloudFront can read from the buckets and an Ordered cache behaviors in CloudFront for different prefixes (/uploads/
, /resized-*/uploads/
). Also, I added 3 origins to my Cloudfront distribution - one for the S3 that hosts the frontend, one each for the bucket that keeps the original image upload, and the one that stores the resized images.
CI/CD with GitHub Actions
Deployed with a workflow triggered on push to main
. My workflow can also be manually triggered to run or destroy my infrastructure using Terraform.
- Applies Terraform
- Syncs frontend files to the S3 bucket
- Secrets like AWS credentials and hosted zone IDs are stored in GitHub Secrets
- name: Deploy Frontend to S3
run: aws s3 sync ./frontend s3://image-resizer.fozdigitalz.com --delete
π Live Project
Check the application with the URL below.
How to Use the Application
- Open the web app β Your browser loads files from CloudFront, which fetches them from a secure S3 bucket.
- Select an image & size β Choose a file and a preset dimension (e.g., Instagramβs 1080x1080).
- Request upload URL β The frontend gets a secure S3 upload link via API Gateway + Lambda.
- Upload directly to S3 β Your browser sends the image to S3 using the generated link.
- Auto-resize triggered β S3 detects the upload, fires a Lambda to resize with Sharp, and saves the result in a resized folder.
- View/download images β Click "Load My Images" to see originals/resized versions, delivered via CloudFront and download the resized if you want.
- Delete anytime β Hit delete, and a Lambda removes the file from S3.
β Results
- Fully functional, scalable image upload and processing system
- No need for EC2 or persistent servers
- Dynamic resize and preview without exposing S3 directly
- CloudFront accelerates delivery globally
π Next Steps
My further enhancements for this project will include the following:
- Auto-tagging via Amazon Rekognition
- Auto-expiring unused images using lifecycle policies
- Authentication using Cognito
- Optimising storage costs with compression and format conversion (e.g., WebP)
- Analytics for site users and image uploads.
π Conclusion
This project was a powerful introduction to building production-grade serverless applications on AWS. With zero backend servers and minimal cost, it delivers a clean UX and powerful functionality β ideal for developers, startups, or any media-heavy app.
π¬ Connect With Me
- Feel free to star, fork, or clone the repository or build your own version.
- Please drop your thoughts in the comment section
- Reach out to me on LinkedIn
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.