How to Learn Serverless AWS by Building 7 Projects: Complete Step by Step Guide
By Braincuber Team
Published on March 31, 2026
Following tutorials when you start learning serverless is a good first step, but to really get better, you need to build your own projects. The problem is that coming up with ideas that are realistic but help you grow is hard. This complete tutorial provides 7 awesome project ideas to progressively help you become a better serverless developer. If you're new to working with Serverless, start with the first projects. If you've built APIs and DynamoDB with Serverless before, pick the projects that cover the topics you want to learn most.
What You'll Learn:
- How to deploy APIs with Lambda and call external APIs
- Building a URL shortener with DynamoDB read/write operations
- Creating a reminder app with DynamoDB TTL and secondary indexes
- Building a live chat app with WebSockets and DynamoDB
- Designing advanced Dynamo tables with Cognito authentication
- Building a messaging app with compound keys and WebSockets
- Creating an event-driven e-commerce system with Event Bridge
Step 1: Build a Combination API Project
This project is designed to get you familiar with deploying an API with Lambda. You'll also practice calling other APIs and merging that data. The architecture is simple but that is exactly what you want as your first project.
Steam Game Deals
Get Steam game deals converted into your local currency. Hit the Steam API, then pass data to a currency conversion API.
Translated News
Get news articles translated into your local language. Hit a news API, then pass the data to a translation API.
The API you create will take parameters through the URL, like this:
https://apiurl.amazonaws.com/dev/steamdeals?currency=EUR
https://apiurl.amazonaws.com/dev/news/fr
The logic is all going to be written into the Lambda. Here's the pseudo-code structure:
const handler = (event: APIGatewayProxyEvent) => {
// get the path or query string parameter value
// hit the first API to get the first data
// get the data you need to translate / convert
// pass the data from API1 into API2
// combine the data
// return data in API Gateway format
}
Free Public APIs Resource
If you need free and public APIs to use, check out the massive collection at github.com/public-apis/public-apis. Build this project using the Serverless Framework or AWS CDK — these tools will make you far more valuable as a developer.
Step 2: Build a URL Shortener Project
This project will get you deploying your first DynamoDB table, then writing and reading data from it. There will be two API endpoints: one to add a new URL to the shortener, and one to give a shortened URL and get the original.
Adding a New URL
Get the original URL from the request body, generate a random 5-character code, write to DynamoDB with {id: code, url: originalUrl}, and return the shortened URL.
Getting a URL by Code
Get the code from the URL path, retrieve from DynamoDB by ID, and return the original URL. Optionally return a 301 redirect for automatic redirection.
// Adding a new URL
const handler = (event: APIGatewayProxyEvent) => {
// get their original url (body of the event)
// generate a random 5 character code
// write to Dynamo - {id: code, url: originalUrl }
// return the url
// (https://{apiurl}.amazonaws.com/dev/get/{code})
}
To get the apiURL, pass it in as an environment variable. With the Serverless Framework, add this to the environment section of your config:
apiUrl: {
"Fn::Join": [
"",
[
"https://",
{ Ref: "HttpApi" },
".execute-api.${self:provider.region}.amazonaws.com",
],
],
}
// Getting a URL by code
const handler = (event: APIGatewayProxyEvent) => {
// get code from the url path
// get from dynamo by ID
// return the original url
}
Pro Tip: Add 301 Redirect
Take this one step further by changing the status code of the getUrl endpoint to return a 301 permanent redirect. You'll need to add some extra headers but this will automatically redirect the user to the desired page.
Step 3: Build a Reminder App Project
This project will teach you about Secondary Indexes in DynamoDB as well as DynamoDB Time-To-Live. You will also get to try either email automation with Amazon Simple Email Service (SES) or text messaging with Simple Notification Service (SNS).
The idea for this app is that you can post a new reminder to the first API endpoint. This writes a new record in DynamoDB with a Global Secondary Index (GSI) so you can get a reminder by ID or query based on the user. It also has a Time-To-Live (TTL) which triggers a Lambda at the time of the reminder.
| id | userId | TTL | notificationType | message |
|---|---|---|---|---|
| 123 | test@gmail.com | 1648277828 | Publish next youtube video | |
| 897 | 447113350882 | 1648842828 | sms | Get More MILK |
The Time-To-Live (TTL) tells DynamoDB that once the time reaches this date, delete the record. Two important notes about TTL:
Use Unix Timestamp in Seconds
Make sure this is the Unix timestamp for the deletion date — but in seconds. new Date('october 20 2022').getTime() will be in milliseconds, so just divide by 1000.
15-Minute Deletion Window
The record will be deleted within a 15-minute window after your TTL, so don't panic if it's been 5 minutes and the record hasn't been deleted yet.
Set up a second Lambda triggered any time a record is deleted from DynamoDB. This sends the message to either their email or phone:
// Send reminder
const handler = async (event: DynamoDBStreamEvent) => {
// get the list of deleted records
// map over each record
// Call SES or SNS to send the reminder
}
The second API endpoint gets all reminders for a user. Make sure you've set up a GSI with a partition key of userId and a sort key of TTL. You could also build a simple front-end app and learn about hosting it in S3 and using CloudFront to distribute it.
Step 4: Build a Live Chat App Project
This project will teach you how to build WebSockets. A user can either create a new "room" or join an existing room. Any messages sent are sent to everyone connected to the room.
WebSockets work slightly differently than regular APIs. Instead of having multiple endpoints, you have one endpoint and different message types:
| Message Type | Category | Description |
|---|---|---|
| connectToRoom | Custom | User joins an existing room |
| createRoom | Custom | User creates a new chat room |
| onMessage | Custom | User sends a message to the room |
| disconnect | Default | User disconnects from WebSocket |
When a user connects to the WebSocket, they can send a connectToRoom or createRoom message. Both create a record in DynamoDB with the user's WebSocket connectionId and the roomId. You'll have a GSI so you can later query to get all users for a roomId.
// onMessage
const handler = (event: WebsocketMessageEvent) => {
// get the user's connectionId
// get the user by connectionId from Dynamo to get the roomId
// query for all users in that roomId
// send the message to all users
// return
}
Finally, the onDisconnect handler is a simple Lambda that just deletes the user's record from DynamoDB. You may want to check in connectToRoom that the room exists first by querying for all users by roomId.
Step 5: Build an Idea Voting App Project
This project will teach you to design and build more advanced DynamoDB tables and also work with Cognito for authentication. The tool allows you to ask your community for ideas and find out which of those are most popular.
This starts with all users needing to sign up to your application. We use Cognito for this so that we can ensure each person can only vote once. You'll need to create four endpoints:
Create a Board
Anyone can create a board. The DynamoDB record is simple: boardId, owner (userId), title, and description.
Add Ideas to a Board
Use a schema with pk (partition key) and sk (sort key). Get all ideas for board 1234 by querying for pk = 1234.
Add Vote to an Idea
Use a junction table pattern with pk = ideaId and sk = userId. Check if user already voted by querying pk = ideaId && sk = userId.
Get Board Details
Query all ideas on the board, then map over each idea to query for all votes. Format and return to the user.
export const handler = async (event: APIGatewayProxyEvent) => {
// get boardId from the request
// query all ideas on the board
// map over each idea
// query for all votes on this idea
// format it all into a nice format
// return to the user
}
Junction Table Pattern
Having a second GSI where the PK and SK are switched is a very common pattern. It allows you to have a many-to-many relationship. You can query for all of B connected to a specific A, and all of A connected to a specific B. This is often called a junction table.
Step 6: Build a Messaging App Project
This project will teach you about DynamoDB compound keys and give you more practice with WebSockets and Cognito. The app allows users to sign up, request to join a room, and see all messages sent in that room. The room owner decides whether to let someone join.
The architecture starts like the live chat application — with a WebSocket connection and Lambdas for onConnect, onDisconnect, createGroup, joinGroup, listMyGroups, handleJoinGroupRequest, and sendMessage.
WebSocket Connect / Disconnect
On connection, verify the user's Cognito token. If invalid, kill the WebSocket. If valid, store a connection record. Delete this record on disconnect using the default $disconnect action.
Create a Group
Create two records: a group record (groupId, groupName, owner) and a group membership record. Query pk = groupId and sk startsWith('user') to get all users for the group.
Joining a Group with Compound Keys
Create an access request record with compound keys: pk = groupId and sk = joinRequest#{userId}. Query to return all access requests for that group.
Send and Store Messages
Query for all users in the group and send the message to all current connections. Store messages with pk = groupId and sk = message#{timestamp}.
When a user logs in, they can get messages they missed while offline. Query where pk = groupId and sk > 'message#{timestamp for yesterday}' to return all messages created since yesterday. Allow them to get older messages by passing up the last message they have, enabling infinite scroll on message history.
Step 7: Build an Event-Driven E-Commerce System
This project will teach you about Event Bridge, plus give you extra practice with DynamoDB table design and services like SES and SNS for email and text. The system has products, filtering, carts, and orders. The key difference is that order placement, order status changes, and delivery updates are all handled through Event Bridge.
Storing Products with Hierarchical Sort Keys
Structure your sort keys to allow a level of hierarchy for your products:
| id | pk | sk | title |
|---|---|---|---|
| productId | clothing | mens#tops#{productId} | Next Slimfit T-Shirt |
| productId | clothing | womens#trousers#{productId} | Levi's Jeans |
This allows you to query for pk = clothing and sk beginsWith mens to get all men's clothes, or pk = clothing and sk beginsWith womens#trousers to get all women's trousers.
Event Bridge Events
orderCreated Event
Two listeners: send order data to warehouse API for packing, and send the user an order confirmation email.
orderPacked Event
Two listeners: email an update to the user, and email a delivery service to collect the parcel from the warehouse.
orderDelivered Event
Two listeners: send a "thank you" message to the customer, and anonymize the order data for data science analysis.
Data Anonymization
Remove personal data and store in another DynamoDB table for data scientists to train recommendation models.
Why Use Event Bridge?
Event Bridge allows you to have events that can trigger multiple Lambdas. This is great because you can add a new listener without having to change the upfront code. Each event can have multiple independent listeners processing in parallel.
Frequently Asked Questions
What is the best way to learn serverless AWS?
The best way to learn serverless AWS is by building progressive projects. Start with simple API + Lambda combinations, then move to DynamoDB, WebSockets, Cognito authentication, and finally Event Bridge for event-driven architectures.
What tools should I use for serverless development?
Use the Serverless Framework or AWS CDK for infrastructure as code. These tools will make you far more valuable as a developer compared to manual console configuration. Both support TypeScript and integrate well with Lambda and API Gateway.
How does DynamoDB Time-To-Live (TTL) work?
TTL tells DynamoDB to delete a record once a specified Unix timestamp (in seconds) is reached. The record is deleted within a 15-minute window after the TTL expires. You can trigger a Lambda via DynamoDB Streams when records are deleted.
What is a junction table pattern in DynamoDB?
A junction table pattern uses a second GSI where the PK and SK are switched. This allows many-to-many relationships — you can query for all of B connected to a specific A, and all of A connected to a specific B. Common in voting and relationship systems.
What is AWS Event Bridge and why use it?
Event Bridge is an event bus service that allows events to trigger multiple Lambda functions. You can add new listeners without changing existing code, making it ideal for order processing, notifications, and decoupled microservice architectures.
Need Help with AWS Serverless Architecture?
Our experts can help you design, implement, and optimize your AWS serverless infrastructure using Lambda, DynamoDB, API Gateway, Event Bridge, and more for maximum scalability and cost efficiency.
