Skip to content

Getting Started

This page walks through installing the provider, configuring a DbContext, mapping an entity to a DynamoDB table, and running your first query and write.

Prerequisites

  • .NET 10 and EF Core 10
  • An AWS account with a DynamoDB table already created, or DynamoDB Local running locally for development
  • AWS credentials resolvable by the standard credential chain — environment variables, ~/.aws/credentials, an IAM instance profile, etc.

The DynamoDB table must exist before the provider can query it. The provider does not create or migrate tables.

Installation

dotnet add package EntityFrameworkCore.DynamoDb

Define an Entity

Each C# class maps to items in a DynamoDB table. Properties map to DynamoDB attributes.

public class Product
{
    public required string Id { get; set; }
    public required string Category { get; set; }
    public required string Name { get; set; }
    public decimal Price { get; set; }
}

Property names map to attribute names as-is by default. See Attribute Naming for conventions and overrides.

Configure DbContext

Direct configuration

Override OnConfiguring to set up the provider inline. This is the quickest path and works well for console apps or tests pointing at DynamoDB Local:

public class ShopContext : DbContext
{
    public DbSet<Product> Products => Set<Product>();

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder.UseDynamo(options =>
            options.ConfigureDynamoDbClientConfig(config =>
            {
                config.ServiceURL = "http://localhost:8000"; // DynamoDB Local
                config.AuthenticationRegion = "us-east-1";
                config.UseHttp = true;
            }));

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>(b =>
        {
            b.ToTable("Products");
            b.HasPartitionKey(p => p.Id);
        });
    }
}

Using dependency injection

OnConfiguring and DI are not mutually exclusive. A context with OnConfiguring can be registered as-is — the container handles lifetime, and the inline configuration handles provider options:

services.AddDbContext<ShopContext>();

You can also pass the provider options through AddDbContext directly, which is useful when you want to supply a pre-configured IAmazonDynamoDB instance (for custom retry policies, endpoints, or credentials):

services.AddDbContext<ShopContext>(options =>
    options.UseDynamo(o => o.DynamoDbClient(dynamoClient)));

See Configuration for all available options.

Map the Entity

Inside OnModelCreating, every entity needs at minimum a table name and a partition key:

modelBuilder.Entity<Product>(b =>
{
    b.ToTable("Products");          // DynamoDB table name — must already exist
    b.HasPartitionKey(p => p.Id);   // partition key attribute
});

If your table has a sort key, declare it too:

b.HasSortKey(p => p.Category);

See Entities and Keys for composite keys, secondary indexes, and owned types.

Run a Query

await using var context = new ShopContext();

// Retrieve all products (full scan — avoid on large tables)
var all = await context.Products.ToListAsync();

// Filter by partition key — efficient; hits a single partition
var product = await context.Products.FirstOrDefaultAsync(p => p.Id == "prod-42");

Always filter on the partition key when possible. Queries without a partition key condition perform a full table scan, which is slow and expensive on large tables.

Save Data

Add

var product = new Product { Id = "prod-99", Category = "hardware", Name = "Widget", Price = 9.99m };
context.Products.Add(product);
await context.SaveChangesAsync();

Update

Mutate a tracked entity — one returned from a query on the same context — and call SaveChangesAsync. EF Core's change tracker detects the modified properties and issues an UPDATE.

var product = await context.Products.FirstOrDefaultAsync(p => p.Id == "prod-99");

product!.Price = 12.99m;
await context.SaveChangesAsync();

Delete

var product = await context.Products.FirstOrDefaultAsync(p => p.Id == "prod-99");

context.Products.Remove(product!);
await context.SaveChangesAsync();

Query execution is async-only

Normal and generated precompiled queries are asynchronous only. Use methods such as ToListAsync() and FirstOrDefaultAsync() for queries and SaveChangesAsync() for writes.

See Also