AWS Builder Center
šŸ—„ļø DynamoDB for Beginners: Building My First Serverless Database in AWS

šŸ—„ļø DynamoDB for Beginners: Building My First Serverless Database in AWS

A beginner-friendly introduction to Amazon DynamoDB, showing how a NoSQL database works and how it can be connected with AWS Lambda to build a simple serverless application.

šŸ—„ļø DynamoDB for Beginners: Building My First Serverless Database in AWS

After learning how to build a serverless API using Amazon API Gateway + AWS Lambda, I reached the next question:
Where do I actually store the application's data?
A Lambda function can process requests, but if I want to build a real application, I need a database.
That's where Amazon DynamoDB comes in.
DynamoDB is a fully managed NoSQL database designed for applications that need fast and scalable data access.
The architecture I wanted to understand was:
1
2
3
4
5
6
7
8
9
10
šŸŒ Client
│
ā–¼
API Gateway
│
ā–¼
AWS Lambda
│
ā–¼
Amazon DynamoDB
This gives me a complete serverless application flow without managing a traditional database server.

🧠 What Is DynamoDB?

Amazon DynamoDB is a managed NoSQL database service.
Instead of thinking about traditional SQL tables with rows and columns, DynamoDB works with:
1
2
3
4
5
6
7
8
9
10
11
Table
│
ā”œā”€ā”€ Item
│ ā”œā”€ā”€ Attribute
│ ā”œā”€ā”€ Attribute
│ └── Attribute
│
└── Item
ā”œā”€ā”€ Attribute
ā”œā”€ā”€ Attribute
└── Attribute
An item is similar to a row.
An attribute is similar to a field.
But DynamoDB is designed differently from a traditional relational database.

šŸ“¦ My First DynamoDB Table

For a simple learning project, I can create a table called:
1
Users
I can use:
1
2
Primary Key:
userId
Then my items could look like:
1
2
3
4
5
6
{
"userId": "101",
"name": "Prince",
"email": "prince@example.com",
"course": "AWS"
}
Another item could be:
1
2
3
4
5
6
{
"userId": "102",
"name": "Alex",
"email": "alex@example.com",
"course": "Cloud Computing"
}
Both items belong to the same table but can contain different attributes.

šŸ”‘ Understanding the Primary Key

One of the most important DynamoDB concepts is the primary key.
In my example:
1
userId
is the partition key.
It uniquely identifies an item in the table when using a simple primary key.
For example:
1
userId = 101
can identify one user.
1
userId = 102
can identify another user.
I started thinking about the primary key as:
"How will my application uniquely find this item?"
That question makes database design much easier.

šŸ†š DynamoDB vs Traditional SQL

Before DynamoDB, I mostly thought about databases like this:
1
2
3
4
5
6
Users
--------------------------------
ID | Name | Email | Course
--------------------------------
1 | John | ... | AWS
2 | Alex | ... | Python
With DynamoDB, I can think more in terms of items:
1
2
3
4
5
{
"userId": "1",
"name": "John",
"course": "AWS"
}
and:
1
2
3
4
5
{
"userId": "2",
"name": "Alex",
"course": "Python"
}
DynamoDB is a NoSQL database, so I need to think about how my application will access the data rather than simply designing tables the same way I might in a relational database.

šŸš€ Connecting Lambda to DynamoDB

This is where the architecture becomes interesting.
Instead of accessing DynamoDB directly from a browser, I can use Lambda as the application layer.
1
2
3
4
5
6
7
8
9
10
šŸŒ Client
│
ā–¼
API Gateway
│
ā–¼
AWS Lambda
│
ā–¼
Amazon DynamoDB
For example:
1
POST /users
could trigger Lambda.
Lambda could then create a new user in DynamoDB.

šŸ Writing Data with Python

The AWS SDK for Python is called Boto3.
A simplified example looks like this:
1
import boto3dynamodb = boto3.resource("dynamodb")table = dynamodb.Table("Users")def lambda_handler(event, context): table.put_item( Item={ "userId": "101", "name": "Prince", "course": "AWS" } ) return { "statusCode": 200, "body": "User created successfully!" }
The Lambda function calls DynamoDB and stores an item in the Users table.

šŸ” Reading Data

I can also retrieve an item.
For example:
1
import boto3dynamodb = boto3.resource("dynamodb")table = dynamodb.Table("Users")def lambda_handler(event, context): response = table.get_item( Key={ "userId": "101" } ) return { "statusCode": 200, "body": str(response.get("Item")) }
The basic flow is:
1
2
3
4
5
6
7
8
9
Lambda
│
│ Get item
ā–¼
DynamoDB
│
│ Return item
ā–¼
Lambda

šŸ” What About Permissions?

This was another important AWS lesson.
My Lambda function shouldn't automatically have unlimited access to AWS services.
Instead, I need to give it appropriate permissions using an IAM role.
For example:
1
2
3
4
5
6
7
8
9
10
Lambda
│
ā–¼
IAM Execution Role
│
ā–¼
DynamoDB Permissions
│
ā–¼
Users Table
The role might allow the Lambda function to perform only the operations it needs.
For example:
1
2
3
4
PutItem
GetItem
UpdateItem
DeleteItem
This follows an important security principle:
Give a workload only the permissions it actually needs.
This connects directly to what I learned in my earlier AWS IAM article.

šŸ”„ Building a Complete Serverless Application

Now I can combine everything I've learned so far.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
šŸŒ User
│
│ HTTPS
ā–¼
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│ API Gateway │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
│
ā–¼
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│ AWS Lambda │
│ Python │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
│
IAM Role
│
ā–¼
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│ DynamoDB │
│ │
│ Users Table │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
This is starting to look like a real application.

šŸ“ Example: User Registration API

Imagine I'm building a simple registration system.
A user sends:
1
POST /users
with:
1
2
3
4
5
{
"userId": "101",
"name": "Prince",
"course": "AWS"
}
The request goes through:
1
2
3
4
5
6
7
Client
↓
API Gateway
↓
Lambda
↓
DynamoDB
DynamoDB stores:
1
2
3
4
5
{
"userId": "101",
"name": "Prince",
"course": "AWS"
}
Now I've created a small but complete serverless backend.

⚔ Why DynamoDB Is Interesting

One thing I like about DynamoDB is that AWS manages the underlying database infrastructure.
I don't need to manually:
  • Install a database server
  • Manage an operating system
  • Configure database hardware
  • Handle traditional server patching
  • Manage database servers myself
Instead, I focus on:
1
2
3
4
5
Data
+
Access patterns
+
Application logic
AWS handles much of the underlying infrastructure.

šŸ“ˆ What About Scaling?

DynamoDB is designed to scale as application requirements grow.
This is especially useful for serverless applications.
For example:
1
2
3
4
5
6
7
8
9
10
Small Application
│
ā–¼
DynamoDB
│
ā–¼
Growing Application
│
ā–¼
DynamoDB
The database service is designed to handle high request volumes without requiring me to manually manage database servers.
That makes it a natural companion for serverless architectures.

šŸ”Ž Query vs Scan

This was another concept I found important.
DynamoDB provides different ways to retrieve data.

Query

A query retrieves items based on a key.
For example:
1
Find user with userId = 101

Scan

A scan examines items across a table.
For large datasets, repeatedly scanning a table can be inefficient.
This taught me an important lesson:
Database design should start with how the application will access the data.
I shouldn't create a DynamoDB table first and only later think about how I'll retrieve the data.

🧠 The Biggest DynamoDB Lesson

With traditional databases, I might start by thinking:
"What tables should I create?"
With DynamoDB, I need to think more about:
"What questions will my application ask the database?"
For example:
1
2
3
4
Get user by userId
Find orders for a customer
Find products by category
Find recent events
Those access patterns influence how I design the table and keys.
That's a very different way of thinking about databases.

āš ļø Common Beginner Mistakes

āŒ Mistake 1: Treating DynamoDB exactly like SQL

DynamoDB is a NoSQL database with a different data-modeling approach.

āŒ Mistake 2: Ignoring access patterns

I should understand how my application will retrieve data before designing the table.

āŒ Mistake 3: Giving Lambda excessive permissions

The Lambda execution role should follow least-privilege principles.

āŒ Mistake 4: Using Scan for everything

Scanning can become inefficient as the amount of data grows.

āŒ Mistake 5: Forgetting about costs

Even serverless services can generate charges.
I should monitor usage and understand the pricing model before moving beyond small experiments.

šŸ”„ My Current AWS Architecture

After learning VPC, subnets, security controls, API Gateway, Lambda, and now DynamoDB, I can visualize a much larger AWS architecture:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
šŸŒ Internet
│
ā–¼
API Gateway
│
ā–¼
AWS Lambda
│
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”
│ │
ā–¼ ā–¼
DynamoDB S3
│ │
ā–¼ ā–¼
Data Objects
Each AWS service has a specific responsibility.
That's making AWS architecture much easier for me to understand.

šŸŽÆ Final Takeaway

My biggest takeaway from learning DynamoDB is that a database doesn't have to mean managing database servers.
With:
1
2
3
4
5
API Gateway
+
Lambda
+
DynamoDB
I can build a complete serverless backend.
The mental model I now use is:
API Gateway receives the request. Lambda processes the logic. DynamoDB stores the data. IAM controls what Lambda is allowed to do.
That's another important step in my AWS learning journey. šŸš€ā˜ļø
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