Best AWS projects to boost your portfolio
Cloud computing powers modern software development, with AWS leading the way as the top cloud provider for scalable, reliable solutions.
➡️ Build real-world projects.
In this blog, I’ll walk you through 5 hands-on AWS projects that not only teach you practical cloud skills but are also great portfolio boosters. You’ll get:
- ✅ Use cases
- ✅ Architecture diagrams
- ✅ Tools involved
- ✅ Code ideas
These projects are beginner-friendly yet powerful enough to be used in startups or enterprise settings. Let’s dive in!
🚀 Project 1: Serverless File Upload System using AWS Lambda & S3
🔹 Objective:
Build a web-based file uploader that stores files directly into an S3 bucket using AWS Lambda and API Gateway.
🔹 Tools Used:
- AWS S3 (storage)
- AWS Lambda (backend logic)
- API Gateway (for exposing API)
- IAM (permissions)
🏗️ Architecture Flow

1. Client Application (Frontend/UI)
- Users interact with the UI to select and upload files for example – image/pdf/text etc.
- The client sends a request to an API to generate a pre-signed S3 upload URL.
- Technologies: React, Angular, Vue.js, or any mobile/web app.
2. Amazon API Gateway
- Acts as the secure entry point to the backend services.
- Routes the request to a Lambda function responsible for generating pre-signed URLs.
- Provides authentication and rate limiting.
3. AWS Lambda – Generate Pre-signed S3 URL
- Stateless function written in Node.js, Python, or Java.
- Validates file metadata (e.g., file type, size).
- Uses AWS SDK (
boto3
or equivalent) to generate a secure, time-limited pre-signed S3 URL. - Returns the URL to the client for direct upload.
4. Amazon S3 – Direct File Upload
- Client uploads the file directly to an S3 bucket using the pre-signed URL.
- Upload bypasses the backend for performance, cost-efficiency, and scalability.
- Files are securely stored in a dedicated S3 bucket.
5. S3 Event Notification (Optional Post-Processing)
- On file upload (
s3:ObjectCreated:*
), an event triggers another AWS Lambda function. - Common use cases:
- File format conversion (e.g., image resizing, video transcoding)
- Virus scanning
- Moving files to Glacier or another bucket
- Metadata extraction and database storage
6. Additional AWS Services (Optional Integrations)
Amazon CloudWatch: Monitor Lambda performance and logs for auditing and debugging.
Amazon SNS/SES: Send notifications (email/SMS) after file upload.
🔹 Why It’s Useful:
This is a real-world pattern used in content platforms, form submissions, etc. You’ll learn how to secure file uploads and handle metadata.
🔐 IAM Permissions for Lambda Role
IAMRole{
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::your-bucket-name/*"
}
🔹 Code Snippet (Python):
import json
import boto3
import os
import uuid
s3_client = boto3.client('s3')
BUCKET_NAME = os.environ['BUCKET_NAME'] # Set this in Lambda config
def lambda_handler(event, context):
try:
# Parse body
body = json.loads(event['body'])
# Generate unique file name (e.g., UUID + extension)
file_extension = body.get('extension', 'jpg')
file_type = body.get('fileType', 'image/jpeg')
file_name = f"{uuid.uuid4()}.{file_extension}"
# Generate pre-signed URL
url = s3_client.generate_presigned_url(
'put_object',
Params={
'Bucket': BUCKET_NAME,
'Key': file_name,
'ContentType': file_type
},
ExpiresIn=300 # URL expires in 5 minutes
)
return {
"statusCode": 200,
"headers": {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
},
"body": json.dumps({
"uploadUrl": url,
"fileName": file_name
})
}
except Exception as e:
return {
"statusCode": 500,
"body": json.dumps({"error": str(e)})
}
🧬 Project 2: Real-Time ETL Pipeline using SNS, SQS, Lambda & Glue
🔹 Objective:
To build a serverless, scalable, and event-driven real-time ETL pipeline that:
Transforms and loads data into a target storage (S3, RDS, Redshift, etc.)
Ingests incoming data events in real-time
Triggers processing automatically
Create a real-time data ingestion pipeline where raw data is transformed and stored for analytics.
🧰 Tools & Services Used
Tool | Purpose |
---|---|
Amazon SNS | Publish/Subscribe for triggering ETL events |
Amazon SQS | Queue to buffer and decouple event messages |
AWS Lambda | Orchestrates the flow and triggers Glue jobs |
AWS Glue | Serverless ETL to transform and load data |
Amazon S3 | Storage for raw and processed data |
IAM | Permissions for services to interact |
CloudWatch | Logs and monitoring |
🔹 Architecture:

🔹 What You’ll Learn:
- Setting up event-driven architecture
- Integrating Glue jobs
- Basic PySpark transformation
🧑💻 Code Snippets
📬 1. Sample SNS Message (Published by app/process)
jsonObject{
"input_path": "s3://my-bucket/raw-data/file.csv"
}
🧾 2. Lambda Function (Python)
pythonCopyEditimport json
import boto3
glue = boto3.client('glue')
def lambda_handler(event, context):
for record in event['Records']:
try:
body = json.loads(record['body'])
sns_message = json.loads(body['Message'])
input_path = sns_message.get('input_path')
if input_path:
response = glue.start_job_run(
JobName='RealTimeETLGlueJob',
Arguments={'--input_path': input_path}
)
print(f"Glue Job Started: {response['JobRunId']}")
else:
print("No input_path found")
except Exception as e:
print(f"Error: {e}")
return {
"statusCode": 200,
"body": "Processed successfully"
}
🧪 3. AWS Glue Job Script (PySpark)
pythonCopyEditimport sys
from awsglue.utils import getResolvedOptions
from awsglue.context import GlueContext
from pyspark.context import SparkContext
args = getResolvedOptions(sys.argv, ['JOB_NAME', 'input_path'])
input_path = args['input_path']
sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
# Read raw CSV data from S3
df = glueContext.create_dynamic_frame.from_options(
connection_type="s3",
format="csv",
connection_options={"paths": [input_path]},
format_options={"withHeader": True}
)
# Example transformation
mapped_df = df.select_fields(['name', 'email'])
# Write processed data to another S3 bucket in Parquet format
glueContext.write_dynamic_frame.from_options(
frame=mapped_df,
connection_type="s3",
format="parquet",
connection_options={"path": "s3://my-bucket/processed-data/"}
)
🧩 Optional Add-ons
- Add a Glue Crawler to catalog data
- Set up Dead Letter Queue for Lambda
- Use Athena or QuickSight to analyze processed data
- Add CloudWatch Alarms for monitoring job failures
Why This Pipeline is Useful
- 🔄 Real-Time: Processes data as soon as it’s available
- ⚙️ Serverless: No need to manage infrastructure
- 🧱 Decoupled: SNS, SQS, Lambda, and Glue handle distinct roles
- 📈 Scalable: Easily handles bursts of traffic or large datasets
- 🛡️ Reliable: SQS ensures no data is lost; messages are retried
- 💰 Cost-Efficient: Pay only for what you use (no idle time)
🌐 Project 3: Host a Static Website on AWS S3 + CloudFront + Route53
✅ Objective
To host a secure, scalable, and fast-loading static website on AWS using:
- Amazon S3 for storing and serving static files (HTML, CSS, JS, images)
- CloudFront as a CDN to deliver content globally with low latency
- Route 53 for custom domain name resolution and routing
- SSL/HTTPS for secure and SEO-friendly traffic
🧰 Tools & Services Used
Tool / Service | Purpose |
---|---|
Amazon S3 | Store static site files (HTML/CSS/JS/images) |
Amazon CloudFront | CDN to cache and distribute content globally |
Amazon Route 53 | DNS service to map domain to CloudFront |
AWS Certificate Manager (ACM) | Provision free SSL certificate |
IAM | Manage roles and policies |
CloudWatch | Logs and monitoring |
🔹 Architecture:

🔹 Use Cases:
- Hosting landing pages
- Resumes/portfolio
- Static documentation websites
🧑💻 Step-by-Step Setup & Code
🪣 1. Create & Configure S3 Bucket
- Create a bucket:
www.yourdomain.com
- Enable static website hosting under “Properties”
- Upload your
index.html
,404.html
, assets - Bucket policy (make files public):
IAMRole{
"Version":"2012-10-17",
"Statement":[{
"Sid":"PublicReadGetObject",
"Effect":"Allow",
"Principal": "*",
"Action":["s3:GetObject"],
"Resource":["arn:aws:s3:::www.yourdomain.com/*"]
}]
}
🌐 2. Set Up CloudFront Distribution
- Origin: S3 website endpoint (e.g.,
http://www.yourdomain.com.s3-website-us-east-1.amazonaws.com
) - Viewer Protocol Policy: Redirect HTTP to HTTPS
- Default Root Object:
index.html
- Error Handling: Customize 404/SPA redirect
✔️ Use ACM (Certificate Manager) to request a public certificate (*.yourdomain.com
)
🌍 3. Configure Route 53
- Create a hosted zone for your domain (
yourdomain.com
) - Add A record (alias) pointing to the CloudFront distribution
- You can also add a www. → non-www redirect via another S3 + CloudFront setup
🔐 4. Enable HTTPS with ACM
- Request certificate in N. Virginia (us-east-1) for CloudFront compatibility
- Validate domain via DNS (Route 53 helps automate this)
- Attach certificate to CloudFront distribution
📁 5. Folder Structure Example
bashCopyEdit/my-static-site
│
├── index.html
├── 404.html
├── about.html
├── style.css
├── /images/
└── /js/
🧾 6. Sample index.html
htmlCopyEdit<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Host a secure, fast, and scalable static website on AWS using S3, CloudFront, and Route53.">
<meta name="keywords" content="AWS static website, S3 CloudFront Route53, HTTPS website, serverless hosting, SEO static site AWS">
<meta name="author" content="Your Name">
<title>Host Static Website on AWS | S3 + CloudFront + Route53</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>🚀 Welcome to My AWS Static Website!</h1>
<p>This site is hosted on S3, served via CloudFront, and secured with HTTPS using Route 53 DNS.</p>
</body>
</html>
🧠 Pro Tips
- Enable GZIP/Brotli compression in CloudFront
- Set Cache-Control headers via metadata or Lambda@Edge
- Add robots.txt and sitemap.xml
- Use CloudFront invalidations after updates
- Automate with GitHub Actions or AWS CodePipeline
📊 Optional Monitoring
- Enable CloudFront logs
- Add CloudWatch alarms for traffic or error spikes
- Use Google Search Console + Google Analytics
💾 Project 4: RDS MySQL Backup Automation using Lambda & CloudWatch
✅ Objective
To automatically take snapshots of Amazon RDS MySQL databases using AWS Lambda functions triggered by CloudWatch Events, ensuring reliable and regular database backups for disaster recovery and data durability.
🧰 Tools & Services Used
Service | Purpose |
---|---|
Amazon RDS (MySQL) | The database instance to back up |
AWS Lambda | Serverless function to automate snapshot creation |
Amazon CloudWatch | Scheduled trigger for Lambda |
IAM | Permissions to allow Lambda access to RDS |
Amazon SNS (optional) | Notification for backup success/failure |
CloudTrail (optional) | Audit logs for backup activity |
🔹 Architecture:

💡 Why This Setup Is Useful
Feature | Benefit |
---|---|
✅ Serverless | No EC2/cron jobs to manage |
🕒 Scheduled | Automated and consistent backups |
🔒 Secure | Controlled with IAM roles |
📦 Snapshot-Based | Full DB backups for restore anytime |
💸 Cost Efficient | Only pay for Lambda runtime & storage |
🧘♂️ Simple | Easy to set up and customize |
🔔 Notifiable | Add alerts via SNS for full monitoring |
🧠 Key Things
- RDS MySQL backup automation
- AWS Lambda RDS snapshot
- CloudWatch scheduled RDS backup
- Automate RDS backup AWS
- RDS MySQL daily snapshot
🧑💻 Lambda Function Code (Python 3.x – boto3)
pythonCopyEditimport boto3
import datetime
import os
rds = boto3.client('rds')
def lambda_handler(event, context):
db_identifier = os.environ['DB_INSTANCE_IDENTIFIER']
timestamp = datetime.datetime.utcnow().strftime('%Y-%m-%d-%H-%M-%S')
snapshot_identifier = f"{db_identifier}-snapshot-{timestamp}"
try:
response = rds.create_db_snapshot(
DBInstanceIdentifier=db_identifier,
DBSnapshotIdentifier=snapshot_identifier
)
print(f"Snapshot {snapshot_identifier} created successfully!")
except Exception as e:
print(f"Failed to create snapshot: {str(e)}")
raise e
🔧 IAM Permissions for Lambda (Minimal Required)
Attach a custom policy or inline policy:
IAMRole{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"rds:CreateDBSnapshot",
"rds:DescribeDBInstances"
],
"Resource": "*"
}
]
}
📆 CloudWatch Scheduler
- Go to CloudWatch > Rules
- Create a new rule with Schedule expression: Example (daily at 1 AM UTC): scssCopyEdit
cron(0 1 * * ? *)
- Set target to your Lambda function
- Enable the rule
📨 (Optional) Add SNS Notification
Add SNS code in Lambda or via CloudWatch alarm for:
- Snapshot success/failure
- Error monitoring
🧼 Cleanup Tip
To avoid snapshot accumulation:
Or create another Lambda to delete snapshots older than X days
Add lifecycle policies
pythonCopyEditimport boto3
import datetime
def lambda_handler(event, context):
rds = boto3.client('rds')
snapshot_id = "backup-" + datetime.datetime.now().strftime("%Y-%m-%d-%H-%M")
rds.create_db_snapshot(
DBSnapshotIdentifier=snapshot_id,
DBInstanceIdentifier='your-db-instance'
)
return {"status": "Backup triggered"}
🔐 Project 5: 🔄 ETL Pipeline with Real-Time Alert Notification using AWS Glue, Lambda, DynamoDB & SES
✅ Objective
Build an ETL pipeline that processes data using AWS Glue, and on success or failure, it triggers a Lambda function to send real-time alerts via email using Amazon SES. The system logs the alerts in DynamoDB for traceability.
Great for:
- Data engineers running nightly Glue jobs
- Monitoring business-critical pipelines
- Getting email alerts for failures or completions
🧰 Tools & Services Used
AWS Service | Purpose |
---|---|
AWS Glue | Extract-Transform-Load (ETL) job |
AWS Lambda | Sends real-time alerts |
Amazon SES | Sends email notifications |
Amazon DynamoDB | Logs alerts and status history |
Amazon CloudWatch Events / EventBridge | Monitors Glue job status |
AWS IAM | Access control for Lambda/Glue/SES |
🔹 Architecture:

✨ Use Case Example
A Glue ETL job loads new customer data into Redshift. On success, an email is sent to the data team. On failure, a different email is sent to DevOps for immediate action.
🔔 Alert Scenarios
- ✅ Job succeeded — log + success email to data team
- ❌ Job failed — log + error email to engineering/devops
- 🔁 Job retries can also be logged
💻 Lambda Function Code (Python – Alert Handler)
pythonCopyEditimport boto3
import os
from datetime import datetime
ses = boto3.client('ses')
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(os.environ['DYNAMO_TABLE'])
def lambda_handler(event, context):
job_name = event['detail']['jobName']
status = event['detail']['state']
timestamp = datetime.utcnow().isoformat()
subject = f"ETL Job {job_name} - {status}"
body = f"The Glue job '{job_name}' has {status} at {timestamp}."
recipient = os.environ['TO_EMAIL']
# Send Email
ses.send_email(
Source=os.environ['FROM_EMAIL'],
Destination={'ToAddresses': [recipient]},
Message={
'Subject': {'Data': subject},
'Body': {'Text': {'Data': body}}
}
)
# Log to DynamoDB
table.put_item(Item={
'jobName': job_name,
'status': status,
'timestamp': timestamp
})
print(f"Notification sent for {job_name} - {status}")
🛠️ Set Up CloudWatch/EventBridge Trigger
- Go to EventBridge → Rules → Create Rule
- Event source: Glue job state change
- Event pattern (example):
jsonCopyEdit{
"source": ["aws.glue"],
"detail-type": ["Glue Job State Change"]
}
- Target: Your Lambda function
🗃️ DynamoDB Schema Example
jobName | status | timestamp |
---|---|---|
etl_customer | SUCCEEDED | 2025-04-06T12:03Z |
etl_orders | FAILED | 2025-04-06T12:04Z |
🔐 IAM Permissions
Lambda role needs access to:
ses:SendEmail
dynamodb:PutItem
logs:*
(for debugging)
🧠 Key Things
- AWS Glue ETL pipeline monitoring
- Real-time ETL job alerts AWS
- Lambda SES notification on Glue job
- ETL job status email AWS
- Glue job monitoring system
🌟 Project Benefits
Feature | Benefit |
---|---|
🧠 Smart Monitoring | Know immediately when ETL jobs fail/succeed |
📬 Real-Time Alerts | No need to manually check logs |
💸 Serverless + Cost-Efficient | No servers to manage |
📊 Auditable | Job history stored in DynamoDB |
🧩 Modular | Easily extend to SMS, Slack, etc. |
Most microservices architectures use this stack. This project gives you full-stack serverless experience.
🎯 Conclusion
Learning AWS isn’t just about certifications. Real growth happens when you build. These 5 AWS projects are perfect for beginners, students, or professionals looking to transition into cloud roles.