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

Architecture diagram of  Server less File Upload System using AWS Lambda & S3

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

ToolPurpose
Amazon SNSPublish/Subscribe for triggering ETL events
Amazon SQSQueue to buffer and decouple event messages
AWS LambdaOrchestrates the flow and triggers Glue jobs
AWS GlueServerless ETL to transform and load data
Amazon S3Storage for raw and processed data
IAMPermissions for services to interact
CloudWatchLogs and monitoring

🔹 Architecture:

Architecture diagram of Real-Time ETL Pipeline using SNS, SQS, Lambda & Glue

🔹 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 / ServicePurpose
Amazon S3Store static site files (HTML/CSS/JS/images)
Amazon CloudFrontCDN to cache and distribute content globally
Amazon Route 53DNS service to map domain to CloudFront
AWS Certificate Manager (ACM)Provision free SSL certificate
IAMManage roles and policies
CloudWatchLogs and monitoring

🔹 Architecture:

Architecture diagram of Host a Static Website on AWS S3 + CloudFront + Route53

🔹 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

ServicePurpose
Amazon RDS (MySQL)The database instance to back up
AWS LambdaServerless function to automate snapshot creation
Amazon CloudWatchScheduled trigger for Lambda
IAMPermissions to allow Lambda access to RDS
Amazon SNS (optional)Notification for backup success/failure
CloudTrail (optional)Audit logs for backup activity

🔹 Architecture:

Architecture diagram of RDS MySQL Backup Automation using Lambda & CloudWatch

💡 Why This Setup Is Useful

FeatureBenefit
✅ ServerlessNo EC2/cron jobs to manage
🕒 ScheduledAutomated and consistent backups
🔒 SecureControlled with IAM roles
📦 Snapshot-BasedFull DB backups for restore anytime
💸 Cost EfficientOnly pay for Lambda runtime & storage
🧘‍♂️ SimpleEasy to set up and customize
🔔 NotifiableAdd 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): scssCopyEditcron(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 ServicePurpose
AWS GlueExtract-Transform-Load (ETL) job
AWS LambdaSends real-time alerts
Amazon SESSends email notifications
Amazon DynamoDBLogs alerts and status history
Amazon CloudWatch Events / EventBridgeMonitors Glue job status
AWS IAMAccess control for Lambda/Glue/SES

🔹 Architecture:

Architecture diagram of ETL Pipeline with Real-Time Alert Notification using AWS Glue, Lambda, DynamoDB & SES

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

  1. Go to EventBridge → Rules → Create Rule
  2. Event source: Glue job state change
  3. Event pattern (example):
jsonCopyEdit{
  "source": ["aws.glue"],
  "detail-type": ["Glue Job State Change"]
}
  1. Target: Your Lambda function

🗃️ DynamoDB Schema Example

jobNamestatustimestamp
etl_customerSUCCEEDED2025-04-06T12:03Z
etl_ordersFAILED2025-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

FeatureBenefit
🧠 Smart MonitoringKnow immediately when ETL jobs fail/succeed
📬 Real-Time AlertsNo need to manually check logs
💸 Serverless + Cost-EfficientNo servers to manage
📊 AuditableJob history stored in DynamoDB
🧩 ModularEasily 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.