Skip to content

DynamoDB

Amazon DynamoDB fully managed NoSQL database service with single-digit millisecond performance at any scale.

Configuration

PropertyValue
ProtocolAwsJson1_0
Signing Namedynamodb
Target PrefixDynamoDB_20120810
PersistenceYes

Quick Start

Create a table, put an item, and retrieve it:

bash
# Create table
curl -s http://localhost:4566 \
  -H "Content-Type: application/x-amz-json-1.0" \
  -H "X-Amz-Target: DynamoDB_20120810.CreateTable" \
  -H "Authorization: AWS4-HMAC-SHA256 Credential=test/20260421/us-east-1/dynamodb/aws4_request, SignedHeaders=host, Signature=fake" \
  -d '{"TableName":"users","KeySchema":[{"AttributeName":"pk","KeyType":"HASH"},{"AttributeName":"sk","KeyType":"RANGE"}],"AttributeDefinitions":[{"AttributeName":"pk","AttributeType":"S"},{"AttributeName":"sk","AttributeType":"S"}],"BillingMode":"PAY_PER_REQUEST"}'

# Put item
curl -s http://localhost:4566 \
  -H "Content-Type: application/x-amz-json-1.0" \
  -H "X-Amz-Target: DynamoDB_20120810.PutItem" \
  -H "Authorization: AWS4-HMAC-SHA256 Credential=test/20260421/us-east-1/dynamodb/aws4_request, SignedHeaders=host, Signature=fake" \
  -d '{"TableName":"users","Item":{"pk":{"S":"user#1"},"sk":{"S":"profile"},"name":{"S":"Alice"},"age":{"N":"30"}}}'

# Get item
curl -s http://localhost:4566 \
  -H "Content-Type: application/x-amz-json-1.0" \
  -H "X-Amz-Target: DynamoDB_20120810.GetItem" \
  -H "Authorization: AWS4-HMAC-SHA256 Credential=test/20260421/us-east-1/dynamodb/aws4_request, SignedHeaders=host, Signature=fake" \
  -d '{"TableName":"users","Key":{"pk":{"S":"user#1"},"sk":{"S":"profile"}}}'

Operations

Table Operations

OperationDescription
CreateTableCreate a table with key schema, billing mode, and optional streams. Returns TableDescription with TableStatus: "ACTIVE" immediately
DeleteTableDelete a table and all its data. Returns TableDescription with TableStatus: "DELETING"
TruncateTableawsim-only. Wipe every item in a table while keeping the schema, indexes, and stream config. No equivalent in real DynamoDB. Input: TableName. Returns { TableName, DeletedItemCount }
DescribeTableGet table metadata: key schema, attribute definitions, item count (live count from SQLite), table size, stream ARN
ListTablesList all tables; supports ExclusiveStartTableName and Limit for pagination
UpdateTableUpdate billing mode (PAY_PER_REQUEST or PROVISIONED) or stream specification
DescribeEndpointsReturn the regional DynamoDB endpoint. Used by SDK endpoint discovery; returns a single endpoint entry

TTL Operations

OperationDescription
DescribeTimeToLiveGet the TTL configuration for a table. Returns TimeToLiveDescription with TimeToLiveStatus and AttributeName
UpdateTimeToLiveEnable or disable TTL on a table. Input: TableName, TimeToLiveSpecification ({Enabled, AttributeName})

Backup Operations

OperationDescription
DescribeContinuousBackupsGet the point-in-time recovery (PITR) status for a table. Returns ContinuousBackupsDescription
UpdateContinuousBackupsEnable or disable PITR for a table
CreateBackupCreate an on-demand backup. Snapshots all items from SQLite into an in-memory record
DeleteBackupDelete a backup. Returns BackupNotFoundException if the backup ARN doesn't exist
DescribeBackupDescribe a backup by ARN
ListBackupsList on-demand backups, optionally filtered by TableName
RestoreTableFromBackupRestore a table from a backup. Creates a new table with the backed-up schema and items
RestoreTableToPointInTimeRestore a table to a point in time. Creates a new table with the source schema (items not copied — point-in-time replay not implemented)

Global Tables

OperationDescription
CreateGlobalTableRegister a global table over per-region replicas. Requires the underlying table to exist in the request region. Input: GlobalTableName, ReplicationGroup (defaults to the request region)
UpdateGlobalTableAdd or remove replicas in one batch. Input: GlobalTableName, ReplicaUpdates: [{Create: {RegionName}}, {Delete: {RegionName}}, ...]
DescribeGlobalTableReturn the stored replication group + status
ListGlobalTablesPaginated by name, optionally filtered by RegionName. Honors ExclusiveStartGlobalTableName and Limit

Export / Import

OperationDescription
DescribeExportDescribe an export by ARN. Returns a stub record
ExportTableToPointInTimeExport to S3 (stub — creates an export record but does not move data to S3)
ListExportsList exports, optionally filtered by TableArn
DescribeImportDescribe an import by ARN. Returns a stub record
ImportTableImport from S3 (stub — creates an import record but does not read from S3)
ListImportsList imports, optionally filtered by TableArn

Account Limits

OperationDescription
DescribeLimitsReturn default account-level throughput limits (called by Terraform on every plan)

Auto Scaling (Terraform compatibility)

OperationDescription
DescribeTableReplicaAutoScalingReturns a stub auto-scaling description for the table. Required by Terraform aws_dynamodb_table plans
UpdateTableReplicaAutoScalingAcknowledges auto-scaling updates without applying them

Global Table Settings (Terraform compatibility)

OperationDescription
DescribeGlobalTableSettingsReturns stub replica settings for a global table
UpdateGlobalTableSettingsAcknowledges global table settings updates without applying them

Contributor Insights

OperationDescription
DescribeContributorInsightsDescribe contributor insights for a table (stub — always returns DISABLED)
UpdateContributorInsightsEnable/disable contributor insights (stub — acknowledges the change)
ListContributorInsightsList contributor insights summaries (stub — returns empty list)

Tagging Operations

OperationDescription
TagResourceAdd tags to a table (by ARN). Input: ResourceArn, Tags list
UntagResourceRemove tags from a table. Input: ResourceArn, TagKeys list
ListTagsOfResourceList all tags for a table. Input: ResourceArn. Returns paginated Tags list

Kinesis Streaming Destination

OperationDescription
EnableKinesisStreamingDestinationRegister a Kinesis stream as a replication destination (metadata only)
DisableKinesisStreamingDestinationRemove a Kinesis streaming destination
DescribeKinesisStreamingDestinationList Kinesis streaming destinations for a table

Resource Policy

OperationDescription
PutResourcePolicyAttach a resource-based policy to a table
GetResourcePolicyRetrieve the resource-based policy for a table
DeleteResourcePolicyRemove the resource-based policy from a table

Item Operations

OperationDescription
PutItemWrite an item. All attributes use DynamoDB type notation: {"S":"string"}, {"N":"123"}, {"BOOL":true}, {"L":[...]}, {"M":{...}}
GetItemRead an item by primary key. Returns Item or empty if not found. Use ProjectionExpression to return subset of attributes
DeleteItemDelete an item by primary key. Use ReturnValues: "ALL_OLD" to get the deleted item back
UpdateItemUpdate specific attributes using UpdateExpression (e.g., SET #name = :val), ExpressionAttributeNames, ExpressionAttributeValues

Query and Scan

OperationDescription
QueryQuery items using KeyConditionExpression on partition key (and optionally sort key). Supports FilterExpression, ProjectionExpression, Limit, ScanIndexForward (ascending/descending), pagination via ExclusiveStartKey
ScanScan all items with optional FilterExpression. Supports Limit, pagination via ExclusiveStartKey. Use sparingly on large tables

Batch Operations

OperationDescription
BatchGetItemRead up to 100 items from one or more tables in one call. Returns Responses (found items) and UnprocessedKeys (retry these)
BatchWriteItemWrite or delete up to 25 items in one call. Mix of PutRequest and DeleteRequest. Returns UnprocessedItems

Transactions

OperationDescription
TransactGetItemsAtomic multi-table read of up to 25 items; all succeed or all fail
TransactWriteItemsAtomic multi-table write of up to 25 items; mix of Put, Update, Delete, ConditionCheck

PartiQL

OperationDescription
ExecuteStatementExecute a single PartiQL statement. Supports basic SELECT, INSERT INTO ... VALUE {...}, UPDATE ... SET, DELETE FROM with simple WHERE equality conditions
BatchExecuteStatementExecute multiple PartiQL statements; returns per-statement results with partial failures
ExecuteTransactionExecute multiple PartiQL statements as an atomic transaction; any failure aborts all

Streams

OperationDescription
DescribeStreamGet stream metadata including shards. Stream ARN is returned in DescribeTable
GetShardIteratorGet a position marker (TRIM_HORIZON, LATEST, AT_SEQUENCE_NUMBER, AFTER_SEQUENCE_NUMBER)
GetRecordsRead change records from a shard; each record has eventName (INSERT, MODIFY, REMOVE) and dynamodb with old/new images
ListStreamsList streams for a table or account

SDK Example

typescript
import {
  DynamoDBClient,
  CreateTableCommand,
  QueryCommand,
} from '@aws-sdk/client-dynamodb';
import {
  DynamoDBDocumentClient,
  PutCommand,
  GetCommand,
  UpdateCommand,
  DeleteCommand,
} from '@aws-sdk/lib-dynamodb';

const client = new DynamoDBClient({
  region: 'us-east-1',
  endpoint: 'http://localhost:4566',
  credentials: { accessKeyId: 'test', secretAccessKey: 'test' },
});

const ddb = DynamoDBDocumentClient.from(client);

// Create table
await client.send(new CreateTableCommand({
  TableName: 'users',
  KeySchema: [
    { AttributeName: 'pk', KeyType: 'HASH' },
    { AttributeName: 'sk', KeyType: 'RANGE' },
  ],
  AttributeDefinitions: [
    { AttributeName: 'pk', AttributeType: 'S' },
    { AttributeName: 'sk', AttributeType: 'S' },
  ],
  BillingMode: 'PAY_PER_REQUEST',
  StreamSpecification: { StreamEnabled: true, StreamViewType: 'NEW_AND_OLD_IMAGES' },
}));

// Put item (Document client handles type marshalling automatically)
await ddb.send(new PutCommand({
  TableName: 'users',
  Item: { pk: 'user#123', sk: 'profile', name: 'Alice', age: 30, tags: ['admin', 'beta'] },
}));

// Get item
const { Item } = await ddb.send(new GetCommand({
  TableName: 'users',
  Key: { pk: 'user#123', sk: 'profile' },
}));
console.log(Item?.name); // Alice

// Update a field
await ddb.send(new UpdateCommand({
  TableName: 'users',
  Key: { pk: 'user#123', sk: 'profile' },
  UpdateExpression: 'SET age = :newAge',
  ExpressionAttributeValues: { ':newAge': 31 },
}));

// Query all items for a user
const { Items } = await client.send(new QueryCommand({
  TableName: 'users',
  KeyConditionExpression: 'pk = :pk',
  ExpressionAttributeValues: { ':pk': { S: 'user#123' } },
}));
console.log('User items:', Items?.length);

CLI Example

bash
# Create table
aws --endpoint-url http://localhost:4566 dynamodb create-table \
  --table-name users \
  --key-schema AttributeName=pk,KeyType=HASH AttributeName=sk,KeyType=RANGE \
  --attribute-definitions AttributeName=pk,AttributeType=S AttributeName=sk,AttributeType=S \
  --billing-mode PAY_PER_REQUEST

# Put item
aws --endpoint-url http://localhost:4566 dynamodb put-item \
  --table-name users \
  --item '{"pk":{"S":"user#1"},"sk":{"S":"profile"},"name":{"S":"Alice"}}'

# Get item
aws --endpoint-url http://localhost:4566 dynamodb get-item \
  --table-name users \
  --key '{"pk":{"S":"user#1"},"sk":{"S":"profile"}}'

# Query
aws --endpoint-url http://localhost:4566 dynamodb query \
  --table-name users \
  --key-condition-expression "pk = :pk" \
  --expression-attribute-values '{":pk":{"S":"user#1"}}'

# Scan with filter
aws --endpoint-url http://localhost:4566 dynamodb scan \
  --table-name users \
  --filter-expression "age > :age" \
  --expression-attribute-values '{":age":{"N":"25"}}'

AWS-defined limits

awsim enforces the same hard limits real AWS DynamoDB does, so SDK code that handles LastEvaluatedKey / UnprocessedKeys / ValidationException works against awsim without modification. Without these caps, an unlimited Query against a fat partition would materialize the whole partition in memory.

OperationLimitBehaviour over the limit
Query / Scan1 MiB responseSet LastEvaluatedKey; client paginates.
BatchGetItem100 keys / 16 MB responseEcho overflow back in UnprocessedKeys for client retry.
TransactGetItems100 actions / 4 MB responseHard ValidationException — transactions don't paginate.
BatchWriteItem25 requests / 400 KB per itemValidationException.
TransactWriteItems100 actionsValidationException.
PutItem / UpdateItem400 KB per item (post-update for UpdateItem)ValidationException.

The byte estimator that drives the response caps walks the typed AttributeValue tree rather than serializing each item — keeps the cap check ~200× faster than to_string() on every accumulated item.

Behavior Notes

  • DynamoDB is persistent: tables and items survive AWSim restarts. Items live in a SQLite database ({data_dir}/dynamodb.db) — see DynamoDB SQLite store for details.
  • Global Secondary Indexes (GSI) and Local Secondary Indexes (LSI) are accepted in CreateTable but queries with IndexName are not yet pushed down to the GSI key columns — they fall back to a full table scan. (The SQLite store materializes up to 5 GSI key column pairs per item, so the data is there; the planner just hasn't been wired to use them yet.)
  • Conditional expressions (ConditionExpression on PutItem, UpdateItem, DeleteItem) are evaluated against the existing item — failed checks return ConditionalCheckFailedException with HTTP 400. When the caller sets ReturnValuesOnConditionCheckFailure: ALL_OLD, the existing Item is attached to the error body so SDKs hydrate it onto the typed exception.
  • TransactWriteItems is genuinely atomic: phase 1 (validate every condition) and phase 2 (apply every mutation) run inside a single SQLite write transaction. A failing condition anywhere in the batch rolls back every mutation that had already been applied. The cancellation surfaces as TransactionCanceledException (HTTP 400) with a structured CancellationReasons array — one entry per TransactItem in request order, marked {"Code": "None"} for unfailed ops and {"Code": "ConditionalCheckFailed", "Message": ...} for the failing one. TransactGetItems reads see a single consistent snapshot.
  • ResourceNotFoundException, TableNotFoundException, BackupNotFoundException, etc. all return HTTP 400 (matching real DynamoDB), not 404. SDK retry/error-classification logic depends on this.
  • Global tables are metadata-only: CreateGlobalTable / UpdateGlobalTable register the replication group so Terraform / CDK can Describe them, but cross-region data replication is not modelled. Reads and writes to the underlying tables stay per-region.
  • TTL (Time to Live) configuration (UpdateTimeToLive) is accepted and stored. A background sweeper periodically deletes expired items from SQLite.
  • DescribeContinuousBackups returns a stub response indicating PITR is disabled — no actual backups are made.
  • DescribeEndpoints returns a single endpoint entry for SDK endpoint discovery compatibility.
  • Table tags (TagResource, UntagResource, ListTagsOfResource) are stored and returned correctly.
  • PartiQL (ExecuteStatement, BatchExecuteStatement, ExecuteTransaction) supports basic SELECT * FROM "Table" WHERE "key" = 'value', INSERT INTO "Table" VALUE {...}, UPDATE "Table" SET attr = val WHERE "key" = 'val', and DELETE FROM "Table" WHERE "key" = 'val'. Full PartiQL expressions, nested paths, and ? parameter binding (with Parameters list) are partially supported.
  • Streams store change records in a bounded in-memory ring buffer (last 1 000 per table); use GetShardIterator with TRIM_HORIZON to read from the beginning. Items themselves live in SQLite.
  • TruncateTable is awsim-only and does not exist in real DynamoDB — guard your code with a feature flag if you also target the real service.
  • Provisioned throughput is enforced. Tables created with BillingMode: PROVISIONED get a per-table token bucket sized at the configured ReadCapacityUnits / WriteCapacityUnits with a 5-minute (300 s) burst window, mirroring real DynamoDB. Once the bucket is drained, further reads / writes return ProvisionedThroughputExceededException (HTTP 400) until tokens refill. UpdateTable with new RCU / WCU rebuilds the bucket immediately. Tables on BillingMode: PAY_PER_REQUEST are never throttled — that is the supported "no throttling" path for code that doesn't want to deal with retry / backoff during local development. Coverage: PutItem / GetItem / UpdateItem / DeleteItem charge by item / response bytes (1 KiB per WCU, 4 KiB per RCU); BatchGetItem / BatchWriteItem charge per touched table; TransactGetItems / TransactWriteItems apply the 2x transactional multiplier; Query / Scan / PartiQL SELECT / INSERT / UPDATE / DELETE are similarly metered.

Released under MIT / Apache-2.0 License