dynobase-icon
Dynobase

DynamoDB C# and .NET: AWS SDK v4 Code Examples

Ravindu Perera

Written by Ravindu Perera

Last updated: October 23rd, 2026

Writing DynamoDB code by hand? Dynobase turns supported data operations into application code or scripts, and generates CDK, CloudFormation or Terraform for an existing table. Code generation in Dynobase

Use AWSSDK.DynamoDBv2 4.x to work with DynamoDB from C# and .NET. It supports the low-level API, the Document model and the object persistence model through DynamoDBContextBuilder. The examples below use asynchronous operations, complete primary keys and explicit pagination, with the nullable response properties introduced in SDK v4.

Choose a programming model

ModelUse it forData representation
Low-level clientFull control over API requests, conditions and transactionsDictionaries of AttributeValue
Document modelFlexible items without a fixed C# entityDocument and Table
Object persistence modelMapping typed entities to tablesAnnotated classes and IDynamoDBContext

All three use the same table and service APIs. A high-level model does not turn a scan into a key lookup or remove the need to handle errors.

Examples

Setup

Use a supported .NET SDK and install the current v4 package. These examples use language features available in .NET 8 or later. The package name still contains DynamoDBv2; that is the service name, not the AWS SDK's major version.

Replace Program.cs with the C# blocks below in order. Each partial-class block adds methods to the same EmployeeStore; the first block supplies shared imports, initialization and a key helper. The initial program constructs the store without making writes. Call individual methods explicitly when testing.

Use the default credential chain, such as a local AWS profile or an IAM role on AWS. Do not hard-code real access keys. The client Region must match the table's Region.

The context builder uses class attributes instead of fetching table metadata by default. The TableBuilder supplies equivalent metadata for Document operations. Neither builder creates an AWS table. Keep their declarations aligned with the actual schema.

Create table and model class

The employee table uses Number empId as its partition key and String JoinedOn as its sort key. Use normalized UTC strings such as 2026-10-23T09:00:00Z consistently so lexical order matches time order. CategoryIndex allows a separate query by category and date.

The C# property can have a different name from the stored attribute. The hash-key annotation maps EmpId to empId; the range-key and index annotations describe the remaining key metadata.

Only key attributes belong in AttributeDefinitions; do not add every entity property. Creation is asynchronous, so the example waits for ACTIVE with a bounded application timeout.

Query

Query selects one partition, optionally restricted by a sort-key condition. This object-model example selects one employee's records from October onward. QueryAsync creates a search; awaiting GetNextSetAsync fetches a page.

For a GSI query, specify the index name and its partition key value, as QueryCategoryAsync does. GSIs support eventual consistency only. A local secondary index can use the same table partition key with a different sort key; its schema must also be declared in the model.

Delete table

Deleting a table is a different operation from deleting an entity. Use the low-level DeleteTableAsync API; it removes all items and indexes. A successful response starts deletion, so wait for absence if a subsequent step requires it.

Delete item

Both models require the complete primary key. An unconditional delete succeeds even if the item is already absent. The object-model version derives the table and key mapping from the class attributes.

Prevent overwriting existing records

A Document-model conditional put inserts only if the item at that complete key is absent. The condition is checked atomically; checking existence in a separate read would leave a race. A failed condition throws ConditionalCheckFailedException.

Use conditional writes for insert-only behavior, optimistic concurrency and state transitions. A condition failure is an application conflict; do not treat it like transient throttling.

Scan

A Scan evaluates table items and then applies its conditions. This filters for internal employees with IDs above 10. It uses async pagination rather than a synchronous enumerable, and an empty filtered page does not end the search.

The filter saves response payload, not the capacity used to evaluate the scanned items. Prefer a query on CategoryIndex when category is the access pattern.

Get items using a query filter

Use sort-key conditions to restrict what DynamoDB reads. Use a filter for other fields, such as FirstName. The object-model filter below is applied after selecting the employee's partition. GetRemainingAsync collects all remaining matches in memory, so use it only for bounded result sets.

Every placeholder must have a matching value or name alias. The Query API reference describes key conditions, filters, sorting and pagination. Set ScanIndexForward = false on the request to reverse sort-key order.

Put item

A low-level PutItem replaces the entire item at that key. ALL_OLD can return the previous item; PutItem cannot return ALL_NEW. Store a DynamoDB null with the NULL attribute-value flag. Empty non-key strings and binary values are allowed, but empty sets and empty key values are not.

SaveAsync persists mapped properties according to its save configuration; it is not a guarantee that concurrent edits are preserved. Use a version property or a low-level condition for concurrency-sensitive changes. Because EmployeeCategory is an index key, give it a nonempty value when saving this model.

Get all items

For small tables, the object model can gather the remaining scan pages into a list. This still performs a Scan, and it still reads every item. For larger tables, process pages as they arrive instead of building an unbounded list.

Get all items with pagination

The Document model exposes a pagination token. Return one page and its token to a caller, then pass that token into the next ScanOperationConfig. Tokens belong to their search configuration; do not interchange them with low-level LastEvaluatedKey maps. See DynamoDB pagination.

The service evaluates up to 1 MB before filtering, and Limit counts evaluated items. A page may contain fewer matches, or none, while still having a continuation token. Scan has no guaranteed ordering and does not provide a point-in-time snapshot.

Get a single item

Load by both key components, and check for an absent result before accessing properties. Use LoadConfig for a strongly consistent base-table read. Do not try to load an item directly by a GSI key; query the GSI instead.

Update item

For a targeted change, use an update expression rather than reading and saving an entire entity. This changes only the email and requires the item to exist. ReturnValues.ALL_NEW returns the resulting attributes.

To update an entity with the object model, load it, change its properties, then call SaveAsync with SaveConfig. That read-modify-write flow needs optimistic locking if multiple writers can edit the same properties.

Batch get items

Batch reads retrieve known keys, not query conditions. Results need not follow request order, and missing items are omitted. Never index into the result list assuming every key was found. The object model handles service batch sizing and unprocessed-key retries; keep a cancellation deadline for the operation.

At the low-level API, one batch supports up to 100 items and a 16 MB response. Retry UnprocessedKeys with backoff until complete or your deadline expires.

Get items from multiple tables

Create a batch for each mapped type, then combine them. The second example table, test_employee_work, must already exist with Number empId and String ProjectId keys. Both tables must be accessible to the same client.

Read each batch's typed Results after the combined execution. Multi-table batch reads are not transactional; use a read transaction when the reads must be atomic.

Batch write items

Object-model batch writes support puts and deletes, not partial updates or per-item conditions. The SDK breaks work into service-sized batches and retries unprocessed writes. The batch as a whole is not atomic.

At the low-level API, explicitly handle UnprocessedItems, use exponential backoff with jitter and retain leftovers if your retry budget expires. Each service request is limited to 25 puts/deletes and 16 MB. Do not put and delete the same key in one batch.

Run transactions

A transaction can atomically check, put, update or delete distinct items. This example requires employee 101 to exist and writes a different employee record. It does not apply a condition check and a write to the same item, which DynamoDB rejects.

Use a stable, unique token for retries of one logical transaction with identical parameters. Its idempotency window lasts 10 minutes after completion. Transactions support up to 100 unique items and 4 MB in one account and Region; MRSC global tables do not support them. A canceled transaction may reflect a condition failure, a conflict or another service validation issue, so inspect the cancellation reasons.

Run DynamoDB Local

Use a local endpoint and dummy credentials for an emulator. The signing Region is still required. Pass the returned client into the same EmployeeStore constructor. Keep this configuration separate from your real AWS profile.

In ASP.NET Core, register a single reusable IAmazonDynamoDB client and an EmployeeStore through dependency injection. For example, put the following registration in Program.cs before building the web application. The web project's implicit imports include dependency-injection extensions:

Use a local development configuration to enable DynamoDb:LocalMode. The production branch uses the default credential chain. The endpoint can be moved into configuration when your emulator runs on another port.

Migrating from SDK v3

AWS SDK for .NET v3 reached end of support on June 1, 2026. When updating to v4:

  • Replace obsolete new DynamoDBContext(client) construction with DynamoDBContextBuilder.
  • Replace DynamoDBOperationConfig overloads with operation-specific QueryConfig, ScanConfig, SaveConfig, LoadConfig and related types.
  • Initialize request dictionaries and lists explicitly. Response collections can be null; check them before iterating.
  • Handle nullable value properties. For example, use response.Count ?? 0, and distinguish an unset nullable Boolean from an explicit false when that distinction matters.
  • Recheck date serialization and custom Document JSON handling. V4 uses UTC retrieval by default and System.Text.Json for Document JSON conversion.

The v4 migration guide lists the breaking changes. The current C# examples provide additional low-level operations. For access-pattern decisions, see Query vs. Scan.

Frequently Asked Questions

Which AWS SDK should I use for DynamoDB in C#?

Use AWSSDK.DynamoDBv2 4.x. The package supports low-level requests, Document operations and typed object persistence; the package name's v2 is not the SDK major version.

Is DynamoDBContext obsolete in .NET v4?

The object persistence model is still supported. Its old public constructors are obsolete; construct the context with DynamoDBContextBuilder and use operation-specific configuration types.

How do I get all DynamoDB items in C#?

Scan with pagination. Use GetNextSetAsync until the high-level search is done, or pass each low-level response's LastEvaluatedKey as the next request's ExclusiveStartKey.

How do I prevent overwriting an item in C#?

Use a conditional put with attribute_not_exists on the partition-key attribute. Handle ConditionalCheckFailedException as a conflict when the item already exists at that complete key.

Why are DynamoDB response properties null after upgrading to v4?

V4 makes request and response value-type properties nullable and lets collections default to null. Initialize request collections explicitly and check response collections before using them.

Dynobase is a Professional GUI Client for DynamoDB

Start your 7-day free trial today

Product Features

Download
/
Changelog
/
Pricing
/
Member Portal
/
Privacy
/
EULA
/
Twitter
© 2026 Dynobase