Skip to main content

AWS DynamoDB with C#: A Complete .NET Tutorial (2026)

Learn how to use AWS DynamoDB with C# in .NET. Step-by-step tutorial with code examples, best practices, and serverless tips. Start building today!

If you are building serverless or cloud-native applications, learning how to use AWS DynamoDB with C# is one of the most valuable skills you can add to your .NET toolkit. DynamoDB is Amazon's fully managed NoSQL database that delivers single-digit millisecond latency at any scale, and it pairs perfectly with .NET workloads running on AWS Lambda, ECS, or EC2. In this DynamoDB C# tutorial, you will learn how to connect, model data, and run CRUD operations using the AWS SDK for .NET — plus the best practices and common pitfalls that trip up most developers.

By the end, you will understand not just how to call DynamoDB from C#, but why the API is designed the way it is, so you can make smart decisions in production.

Why Use AWS DynamoDB with C# and .NET?

Relational databases like SQL Server are excellent for normalized, relational data with complex joins. But for high-throughput, horizontally scalable workloads — think user sessions, shopping carts, IoT telemetry, gaming leaderboards, or event logging — a NoSQL database is often a better fit. Here is why DynamoDB shines for serverless .NET applications:

  • Fully managed: No servers to patch, no replicas to configure. AWS handles availability and durability across multiple Availability Zones.
  • Predictable performance: Single-digit millisecond reads and writes regardless of table size.
  • Serverless-friendly: On-demand capacity mode means you pay per request — ideal for spiky AWS Lambda workloads with no idle cost.
  • Auto-scaling: DynamoDB scales throughput up and down automatically, so you never provision for peak and pay for it 24/7.

Because DynamoDB charges for read/write capacity rather than CPU time, it complements the per-invocation billing model of serverless functions almost perfectly.

Setting Up the AWS SDK for .NET

To talk to DynamoDB from C#, you need the AWS SDK for .NET. The relevant NuGet package is AWSSDK.DynamoDBv2. Install it via the .NET CLI:

// Run in your terminal
// dotnet add package AWSSDK.DynamoDBv2

using Amazon;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;
using Amazon.DynamoDBv2.DocumentModel;
using Amazon.DynamoDBv2.Model;

The SDK resolves credentials automatically using the default credential chain: environment variables, shared ~/.aws/credentials files, or — best of all in production — IAM roles attached to your Lambda function or EC2 instance. Never hard-code AWS access keys in your source code.

Creating the client is straightforward:

// The client picks up credentials from the default chain automatically
var client = new AmazonDynamoDBClient(RegionEndpoint.USEast1);

Three Programming Models You Should Know

One thing that confuses newcomers to AWS DynamoDB in C# is that the SDK exposes three distinct APIs, layered from low-level to high-level:

  • Low-level API (AmazonDynamoDBClient): Full control, but verbose. You work with AttributeValue dictionaries.
  • Document model (Table, Document): A middle ground using flexible JSON-like documents.
  • Object persistence model (DynamoDBContext): An ORM-style mapper that turns C# classes into DynamoDB items. This is the most productive for most apps.

We will focus on the object persistence model with DynamoDBContext, then show the low-level API for queries that need precision.

Modeling Data: Mapping a C# Class to a DynamoDB Table

DynamoDB tables require a primary key, which is either a single partition key (hash key) or a composite of a partition key plus a sort key (range key). Choosing the right key is the single most important design decision in DynamoDB, because it determines how data is distributed and queried.

Here is a Product class decorated with DynamoDB attributes:

[DynamoDBTable("Products")]
public class Product
{
    [DynamoDBHashKey]                 // Partition key
    public string Category { get; set; }

    [DynamoDBRangeKey]                // Sort key
    public string ProductId { get; set; }

    [DynamoDBProperty]
    public string Name { get; set; }

    [DynamoDBProperty]
    public decimal Price { get; set; }

    [DynamoDBProperty]
    public int StockCount { get; set; }

    [DynamoDBProperty("tags")]       // Custom attribute name
    public List Tags { get; set; }
}

With Category as the partition key and ProductId as the sort key, you can efficiently fetch all products in a category, sorted by their ID — without scanning the whole table.

CRUD Operations: A Complete DynamoDB C# Example

Now let's run the four core operations. First, wrap the client in a DynamoDBContext:

var client = new AmazonDynamoDBClient(RegionEndpoint.USEast1);
var context = new DynamoDBContext(client);

Create and Update (SaveAsync)

In DynamoDB, writing an item that already exists overwrites it. The same SaveAsync method handles both insert and update — this is an "upsert" by default.

var product = new Product
{
    Category = "Electronics",
    ProductId = "PROD-1001",
    Name = "Wireless Headphones",
    Price = 79.99m,
    StockCount = 120,
    Tags = new List { "audio", "bluetooth" }
};

await context.SaveAsync(product);
Console.WriteLine("Product saved.");

Read (LoadAsync)

To read a single item, supply the full primary key. Because we have a composite key, you must pass both the partition key and the sort key:

var item = await context.LoadAsync("Electronics", "PROD-1001");

if (item != null)
{
    Console.WriteLine($"{item.Name} costs {item.Price:C}");
}

Delete (DeleteAsync)

await context.DeleteAsync("Electronics", "PROD-1001");
Console.WriteLine("Product deleted.");

Query vs. Scan: The Most Important Performance Lesson

This is where many developers learning AWS DynamoDB with C# make costly mistakes. DynamoDB offers two ways to retrieve multiple items, and they are not interchangeable:

  • Query — reads items by partition key (and optionally filters on the sort key). It is fast and only reads the items you target.
  • Scan — reads every item in the table, then filters. It is slow and expensive on large tables.

Rule of thumb: use Query whenever possible and avoid Scan in production code paths. A Scan on a million-item table consumes read capacity for all million items even if you only want ten of them.

Here is an efficient query that fetches all electronics priced above a threshold using the object persistence model:

var query = context.QueryAsync(
    "Electronics",                                  // Partition key value
    new DynamoDBOperationConfig
    {
        QueryFilter = new List
        {
            new ScanCondition("Price", ScanOperator.GreaterThan, 50.00m)
        }
    });

var results = await query.GetRemainingAsync();

foreach (var p in results)
{
    Console.WriteLine($"{p.Name}: {p.Price:C}");
}

Note that the query targets a single partition ("Electronics") first, so DynamoDB reads only that partition. The price condition is applied as a filter after the key match — filters reduce the data returned, not the data read, so design your keys so the partition itself is selective.

Low-Level Query with Expression Attributes

For maximum control — for example, paginating with LastEvaluatedKey — drop to the low-level API:

var request = new QueryRequest
{
    TableName = "Products",
    KeyConditionExpression = "Category = :cat AND begins_with(ProductId, :prefix)",
    ExpressionAttributeValues = new Dictionary
    {
        [":cat"] = new AttributeValue { S = "Electronics" },
        [":prefix"] = new AttributeValue { S = "PROD-" }
    }
};

var response = await client.QueryAsync(request);
Console.WriteLine($"Found {response.Count} items.");

Best Practices for DynamoDB in .NET Applications

Following these best practices will save you money and prevent production headaches:

  • Reuse the client. AmazonDynamoDBClient is thread-safe and expensive to create. Instantiate it once (as a singleton or a static field) and reuse it across requests. In ASP.NET Core, register it with the DI container via AddAWSService<IAmazonDynamoDB>().
  • Use on-demand capacity for unpredictable traffic. It removes the need to forecast throughput and is ideal for serverless apps.
  • Design single-table schemas. Advanced DynamoDB users often store multiple entity types in one table using composite keys and Global Secondary Indexes (GSIs) to minimize round trips.
  • Use Global Secondary Indexes for alternate access patterns. If you need to query by an attribute that is not your primary key, create a GSI rather than resorting to a Scan.
  • Batch your reads and writes. Use BatchGet and BatchWrite to handle up to 25 writes or 100 reads per call and reduce network overhead.
  • Always handle ProvisionedThroughputExceededException. The SDK retries with exponential backoff automatically, but you should still design for throttling under load.

Common Pitfalls to Avoid

  • Overusing Scan: The number one cause of high DynamoDB bills. Audit your code for ScanAsync calls.
  • Hot partitions: If one partition key value gets disproportionate traffic (e.g., a single popular category), you create a throughput bottleneck. Distribute access by choosing high-cardinality partition keys.
  • Forgetting eventual consistency: By default, reads are eventually consistent and may return slightly stale data. Pass a consistent-read option when you need the latest write.
  • Storing huge items: DynamoDB items max out at 400 KB. Store large blobs in Amazon S3 and keep only a reference in DynamoDB.

Local Development with DynamoDB Local

You do not need a live AWS account to develop. DynamoDB Local runs in Docker and lets you test without incurring charges. Just point your client at it:

var config = new AmazonDynamoDBConfig
{
    ServiceURL = "http://localhost:8000"
};
var client = new AmazonDynamoDBClient("dummy", "dummy", config);

This makes your unit and integration tests fast, free, and isolated from production data.

Conclusion: Key Takeaways

Using AWS DynamoDB with C# unlocks a fully managed, infinitely scalable NoSQL database that fits serverless .NET applications like a glove. Here are the key takeaways from this tutorial:

  • Install AWSSDK.DynamoDBv2 and prefer the high-level DynamoDBContext for productive CRUD operations.
  • Choose your partition and sort keys carefully — they define your access patterns.
  • Always favor Query over Scan to keep latency and costs low.
  • Reuse a single thread-safe client, use on-demand capacity for spiky workloads, and reach for Global Secondary Indexes instead of scanning.
  • Develop and test locally with DynamoDB Local before deploying to the cloud.

With these fundamentals and best practices, you are ready to build fast, cost-effective, serverless .NET applications on DynamoDB. Start small with a single table, measure your read/write capacity, and scale with confidence. Happy coding!

About csharp-coder.com
Your go-to resource for C#, .NET, and modern software development. Follow along for daily tutorials, tips, and real-world examples.

Comments

Popular posts from this blog

.NET MAUI Tutorial 2026: Build Cross-Platform Apps in C#

Learn .NET MAUI in 2026 to build iOS, Android, Windows & Mac apps from one C# codebase. Start this cross-platform tutorial with code examples today. .NET MAUI (Multi-platform App UI) is Microsoft's framework for building native iOS, Android, Windows, and macOS apps from a single C# codebase . If you've ever wanted to ship a mobile app without learning Swift, Kotlin, and Win32 separately, this .NET MAUI tutorial for 2026 is your starting point. In this guide you'll learn what .NET MAUI is, why it matters for cross-platform app development in C#, and how to build your first working app — with runnable code examples and the best practices senior engineers actually use in production. What Is .NET MAUI and Why Use It in 2026? .NET MAUI is the evolution of Xamarin.Forms, fully integrated into the modern .NET runtime. With one project and one language — C# — you target four platforms. The framework compiles to native UI controls on each device, so a button on iOS...

Angular 14 : 404 error during refresh page after deployment

In this article, We will learn how to solve 404 file or directory not found angular error in production.  Refresh browser angular 404 file or directory not found error You have built an Angular app and created a production build with ng build --prod You deploy it to a production server. Everything works fine until you refresh the page. The app throws The requested URL was not found on this server message (Status code 404 not found). It appears that angular routing not working on the production server when you refresh the page. The error appears on the following scenarios When you type the URL directly in the address bar. When you refresh the page The error appears on all the pages except the root page.   Reason for the requested URL was not found on this server error In a Multi-page web application, every time the application needs to display a page it has to send a request to the web server. You can do that by either typing the URL in the address bar, clicking on the Me...

Angular 14 CRUD Operation with Web API .Net 6.0

How to Perform CRUD Operation Using Angular 14 In this article, we will learn the angular crud (create, read, update, delete) tutorial with ASP.NET Core 6 web API. We will use the SQL Server database and responsive user interface for our Web app, we will use the Bootstrap 5. Let's start step by step. Step 1 - Create Database and Web API First we need to create Employee database in SQL Server and web API to communicate with database. so you can use my previous article CRUD operations in web API using net 6.0 to create web API step by step. As you can see, after creating all the required API and database, our API creation part is completed. Now we have to do the angular part like installing angular CLI, creating angular 14 project, command for building and running angular application...etc. Step 2 - Install Angular CLI Now we have to install angular CLI into our system. If you have already installed angular CLI into your system then skip this step.  To install angular CLI ope...