AWS Builder Center
Building a Serverless Web Application with Amazon S3, AWS Lambda, and Amazon DynamoDB

Building a Serverless Web Application with Amazon S3, AWS Lambda, and Amazon DynamoDB

Learn how to build a scalable serverless web application using Amazon S3, Amazon API Gateway, AWS Lambda, and Amazon DynamoDB. This hands-on guide explains the architecture, implementation, security best practices, testing, monitoring, and cost considerations.

Building a Serverless Web Application with Amazon S3, AWS Lambda, and Amazon DynamoDB

Abstract

Modern web applications need to be scalable, reliable, secure, and cost-effective. Traditional applications often require developers to manage servers, operating systems, networking, and infrastructure. Serverless architecture provides an alternative by allowing developers to focus primarily on application logic while AWS manages the underlying infrastructure.
This article demonstrates how to build a simple serverless web application using Amazon S3, AWS Lambda, Amazon DynamoDB, and Amazon API Gateway. The application allows users to submit information through a web interface, sends the request to an API, processes it with AWS Lambda, and stores the data in DynamoDB.
The solution demonstrates how multiple AWS services can work together to create a scalable application without managing traditional servers.

1. Introduction

Building and maintaining web applications traditionally requires servers to host application code, databases, and other components. As application traffic changes, developers may need to provision additional resources or configure auto-scaling mechanisms.
A serverless architecture reduces much of this infrastructure management.
With AWS serverless services, developers can deploy application components without managing physical servers or virtual machines. AWS handles tasks such as infrastructure provisioning, availability, and scaling for supported services.
In this project, we will build a simple serverless application with the following workflow:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
User
|
v
Amazon S3
|
v
Web Application
|
v
Amazon API Gateway
|
v
AWS Lambda
|
v
Amazon DynamoDB
The web application is hosted using Amazon S3. When a user submits data, the application sends an HTTP request to Amazon API Gateway. API Gateway invokes an AWS Lambda function, which processes the request and stores the information in Amazon DynamoDB.

2. Architecture Overview

The application consists of four primary AWS services.

Amazon S3

Amazon Simple Storage Service (Amazon S3) provides object storage. In this application, S3 can host the static files required by the web application, such as:
  • HTML
  • CSS
  • JavaScript
  • Images
Because the application is static on the frontend, no web server is required to serve these files.

Amazon API Gateway

Amazon API Gateway provides an HTTP API endpoint that the frontend can call.
For example:
1
POST /users
The API receives the request and invokes the Lambda function.

AWS Lambda

AWS Lambda runs the application logic without requiring developers to provision or manage servers.
The Lambda function receives the request from API Gateway, validates the data, and writes it to DynamoDB.

Amazon DynamoDB

Amazon DynamoDB is a managed NoSQL database service.
In this example, DynamoDB stores information submitted by users.

3. Prerequisites

Before starting, you should have:
  • An AWS account
  • Basic knowledge of HTML and JavaScript
  • Basic knowledge of JSON
  • Familiarity with the AWS Management Console
  • A basic understanding of AWS IAM permissions
You should also understand that AWS services can incur charges depending on usage. Review AWS pricing and use appropriate limits and monitoring for your environment.

4. Creating the DynamoDB Table

The first step is to create a DynamoDB table.
Open the AWS Management Console and navigate to Amazon DynamoDB.
Create a table with the following configuration:
1
2
3
Table name: ServerlessUsers
Partition key: userId
Partition key type: String
The userId attribute will uniquely identify each item.
A sample item could look like:
1
2
3
4
5
{
"userId": "1001",
"name": "Alex",
"email": "alex@example.com"
}
DynamoDB is schema-flexible, so additional attributes can be stored as needed.

5. Creating the Lambda Function

Next, create an AWS Lambda function.
Navigate to AWS Lambda and choose Create function.
For this example, use:
1
2
Function name: ServerlessUserFunction
Runtime: Python
The Lambda function receives data from API Gateway and stores it in DynamoDB.
Example Python code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import json
import uuid
import boto3

dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table("ServerlessUsers")

def lambda_handler(event, context):
try:
body = json.loads(event.get("body", "{}"))

name = body.get("name")
email = body.get("email")

if not name or not email:
return {
"statusCode": 400,
"body": json.dumps({
"message": "Name and email are required"
})
}

user_id = str(uuid.uuid4())

table.put_item(
Item={
"userId": user_id,
"name": name,
"email": email
}
)

return {
"statusCode": 201,
"headers": {
"Content-Type": "application/json"
},
"body": json.dumps({
"message": "User created successfully",
"userId": user_id
})
}

except Exception as error:
print(error)

return {
"statusCode": 500,
"body": json.dumps({
"message": "Internal server error"
})
}
This function performs the following operations:
  1. Reads the request body.
  2. Extracts the user's name and email.
  3. Validates that both values exist.
  4. Generates a unique ID.
  5. Writes the item to DynamoDB.
  6. Returns an HTTP response.

6. Configuring IAM Permissions

The Lambda function needs permission to write data to DynamoDB.
The recommended approach is to give the Lambda execution role only the permissions required by the application.
For example, a policy could allow the Lambda function to perform PutItem on the specific DynamoDB table.
A simplified policy example is:
1
2
3
4
5
6
7
8
9
10
11
12
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:PutItem"
],
"Resource": "arn:aws:dynamodb:REGION:ACCOUNT_ID:table/ServerlessUsers"
}
]
}
Replace:
1
2
REGION
ACCOUNT_ID
with the appropriate values for your AWS environment.
Avoid granting broad permissions such as:
1
dynamodb:*
when the application only requires a single operation.
This principle is known as least privilege.

7. Creating the API

Now create an API using Amazon API Gateway.
Create an HTTP API and configure a route such as:
1
POST /users
Integrate this route with the Lambda function:
1
2
3
4
5
6
7
8
9
10
POST /users
|
v
API Gateway
|
v
ServerlessUserFunction
|
v
DynamoDB
When a client sends a POST request to the endpoint, API Gateway invokes the Lambda function.
The request body can contain:
1
2
3
4
{
"name": "Alex",
"email": "alex@example.com"
}
The Lambda function processes this information and stores it in DynamoDB.

8. Creating the Frontend

The frontend can be a simple HTML page.
Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<!DOCTYPE html>
<html>
<head>
<title>Serverless User Registration</title>
</head>

<body>

<h1>User Registration</h1>

<form id="userForm">

<label>Name:</label>
<input type="text" id="name" required>

<br><br>

<label>Email:</label>
<input type="email" id="email" required>

<br><br>

<button type="submit">Submit</button>

</form>

<p id="message"></p>

<script>

const API_URL = "YOUR_API_GATEWAY_URL/users";

document.getElementById("userForm").addEventListener("submit", async function(event) {

event.preventDefault();

const name = document.getElementById("name").value;
const email = document.getElementById("email").value;

try {

const response = await fetch(API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
name: name,
email: email
})
});

const result = await response.json();

document.getElementById("message").textContent =
result.message || "Request completed.";

} catch (error) {

console.error(error);

document.getElementById("message").textContent =
"An error occurred.";

}

});

</script>

</body>
</html>
Replace:
1
YOUR_API_GATEWAY_URL
with the API endpoint created in API Gateway.

9. Hosting the Frontend with Amazon S3

The HTML file can be stored in an S3 bucket.
Create a bucket with a globally unique name, for example:
1
my-serverless-web-application
Upload:
1
index.html
and any additional frontend assets.
For production applications, consider using Amazon CloudFront in front of S3 for content delivery and HTTPS.
A typical production architecture could therefore be:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
┌───────────────┐
│ User │
└───────┬───────┘
|
v
┌───────────────┐
│ CloudFront │
└───────┬───────┘
|
v
┌───────────────┐
│ S3 │
│ Static Web App│
└───────────────┘

User submits data
|
v
┌───────────────────┐
│ API Gateway │
└─────────┬─────────┘
|
v
┌───────────────────┐
│ AWS Lambda │
└─────────┬─────────┘
|
v
┌───────────────────┐
│ DynamoDB │
└───────────────────┘

10. Testing the Application

After configuring the services, test the complete workflow.
Open the frontend application and enter:
1
2
Name: Alex
Email: alex@example.com
Click Submit.
The request should follow this path:
1
2
3
4
5
6
7
8
9
Browser
↓
S3-hosted frontend
↓
API Gateway
↓
Lambda
↓
DynamoDB
Check the DynamoDB table to verify that a new item was created.
An example item is:
1
2
3
4
5
{
"userId": "generated-uuid",
"name": "Alex",
"email": "alex@example.com"
}

11. Error Handling

Applications should handle errors gracefully.
For example, if the user does not provide an email address, the Lambda function returns:
1
2
3
{
"message": "Name and email are required"
}
with an HTTP status code of:
1
400
Unexpected application errors can return:
1
500 Internal Server Error
Application logs can be reviewed using Amazon CloudWatch Logs.
CloudWatch can help developers troubleshoot problems such as:
  • Lambda execution errors
  • Invalid input
  • API failures
  • Unexpected exceptions
  • Application performance issues

12. Security Best Practices

Security should be considered throughout the application lifecycle.

Use least-privilege IAM permissions

Give each AWS resource only the permissions it requires.
For example, if Lambda only needs to write records, it does not need full DynamoDB administration permissions.

Validate input

Never assume that input received from users is valid.
Validate:
  • Required fields
  • Email format
  • Maximum input length
  • Expected data types

Protect sensitive information

Do not store passwords, API keys, or other secrets directly in source code.
Use appropriate AWS services and mechanisms for managing secrets and sensitive configuration.

Use HTTPS

Applications should use encrypted communication.
API Gateway provides HTTPS endpoints, and production web applications should use secure delivery mechanisms such as CloudFront with HTTPS.

Monitor the application

Use Amazon CloudWatch to monitor Lambda execution and application behavior.
Monitoring helps identify failures and unusual activity.

13. Scalability

One of the major advantages of this architecture is scalability.
Traditional applications may require developers to manage server capacity as traffic changes.
In a serverless architecture, services such as Lambda and DynamoDB are designed to support variable workloads using AWS-managed infrastructure.
For example:
1
2
3
4
5
6
7
8
9
10
11
Low traffic
↓
Few requests
↓
Serverless services process requests

High traffic
↓
More requests
↓
AWS services can scale according to their service-specific capabilities and configuration
The exact scaling behavior and limits depend on the AWS service, configuration, quotas, and workload.

14. Cost Considerations

Serverless architectures can be cost-effective because many AWS services use usage-based pricing models.
Instead of maintaining a continuously running application server, you generally pay for the resources consumed by the services.
However, serverless does not automatically mean free.
Costs can result from:
  • Lambda invocations and compute duration
  • API Gateway requests
  • DynamoDB usage
  • S3 storage and requests
  • Data transfer
  • CloudFront usage
  • CloudWatch logs and other monitoring resources
Before deploying an application, review the current AWS pricing information for each service and configure budgets or alerts where appropriate.

15. Advantages of the Architecture

This architecture provides several benefits.

No server management

Developers do not need to manage traditional application servers for the Lambda backend.

Automatic scaling

AWS manages scaling behavior for supported serverless services according to their service models and configuration.

Reduced operational overhead

Developers can focus on application functionality instead of operating servers.

Independent components

The frontend, API, compute layer, and database are separate components.
This separation can make the application easier to maintain and evolve.

Pay-for-use model

Many components use consumption-based pricing, which can be beneficial for applications with variable or intermittent traffic.

16. Possible Improvements

The basic application can be extended in several ways.

Add authentication

Amazon Cognito can be introduced to authenticate users and control access to application resources.

Add a GET API

A second API route could retrieve user information:
1
GET /users

Add update and delete operations

The application could support:
1
2
3
4
POST /users
GET /users
PUT /users/{id}
DELETE /users/{id}
This would provide complete CRUD functionality.

Add CloudFront

CloudFront can improve content delivery for users in different geographic locations.

Add monitoring and alarms

CloudWatch metrics and alarms can be used to monitor errors and application health.

Infrastructure as Code

For repeatable deployments, the infrastructure can be defined using services and tools such as AWS CloudFormation or AWS CDK.

17. Key Takeaways

This project demonstrates how AWS managed services can be combined to create a serverless web application.
The main workflow is:
1
2
3
4
5
6
7
8
9
Amazon S3
↓
Web Application
↓
Amazon API Gateway
↓
AWS Lambda
↓
Amazon DynamoDB
Each service has a specific responsibility:
AWS ServiceResponsibility
Amazon S3Hosts static website files
Amazon API GatewayProvides API endpoints
AWS LambdaRuns application logic
Amazon DynamoDBStores application data
Amazon CloudWatchProvides monitoring and logs
Amazon CloudFrontCan provide global content delivery
The architecture eliminates the need to manage traditional application servers while providing a foundation that can be extended as application requirements grow.

18. Conclusion

Serverless architecture provides a practical approach for building modern cloud applications without managing traditional servers.
By combining Amazon S3, API Gateway, AWS Lambda, and DynamoDB, developers can create a complete application using managed AWS services. The architecture separates the frontend, API, compute, and data layers, making it easier to develop and maintain the application.
The same principles can be applied to many real-world use cases, including registration systems, feedback applications, dashboards, REST APIs, and lightweight backend services.
As the application grows, additional AWS services can be introduced for authentication, monitoring, content delivery, automation, and infrastructure management.
The most important lesson is that serverless architecture is not simply about removing servers. It is about choosing managed services that allow developers to focus on business logic while AWS handles much of the underlying infrastructure.

References

  1. AWS Documentation — Amazon S3
  2. AWS Documentation — AWS Lambda
  3. AWS Documentation — Amazon API Gateway
  4. AWS Documentation — Amazon DynamoDB
  5. AWS Documentation — AWS Identity and Access Management (IAM)
  6. AWS Documentation — Amazon CloudWatch
  7. AWS Documentation — Amazon CloudFront
  8. AWS Well-Architected Framework
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article