Overcast is alpha — behaviour and APIs may change between releases. Pin your version and read the changelog before upgrading.

overcast

DynamoDB — Amazon DynamoDB

Quick start, item, expression, index and transaction coverage, the metrics recorded, and the divergences: immediately consistent GSIs, swept TTL, no PartiQL, no global tables.

Full item, expression, index and transaction support, with tables scoped to a region exactly as on AWS.

Status: ✅ Supported

Quick start

export AWS_ENDPOINT_URL=http://localhost:4566

aws dynamodb create-table --table-name orders \
  --attribute-definitions AttributeName=id,AttributeType=S \
  --key-schema AttributeName=id,KeyType=HASH \
  --billing-mode PAY_PER_REQUEST

aws dynamodb put-item --table-name orders \
  --item '{"id": {"S": "o-1"}, "total": {"N": "42"}}'
aws dynamodb get-item --table-name orders --key '{"id": {"S": "o-1"}}'

Any credentials work; with none configured, run eval "$(overcast env)" first — see Using AWS SDKs and CLI.

What works

AreaBehaviour
ItemsPutItem, GetItem, UpdateItem, DeleteItem, BatchGetItem (100), BatchWriteItem (25)
ExpressionsCondition, filter, key-condition, projection and update expressions, with SET/REMOVE/ADD/DELETE and every ReturnValues variant; a reserved word used as a bare attribute name is rejected as AWS rejects it, so reach it through ExpressionAttributeNames
Query and scanLimit applied before FilterExpression as AWS does, ExclusiveStartKey pagination, ScanIndexForward, Select=COUNT, parallel scan by Segment/TotalSegments
IndexesGSIs and LSIs, including ALL/KEYS_ONLY/INCLUDE projections and GSI create/delete/throughput updates through UpdateTable
Request validationThe rejections AWS documents, with AWS’s wording: AttributeDefinitions must match the key schemas exactly, key attributes may not be empty, a Query must constrain the partition key, items are capped at 400 KB by AWS’s size accounting, BatchWriteItem and TransactWriteItems refuse two operations on one item, BatchGetItem refuses more than 100 keys, and Scan refuses a Segment at or past TotalSegments
TransactionsTransactGetItems and TransactWriteItems, all-or-nothing, with ConditionCheck
Billing modesAn omitted BillingMode defaults to PROVISIONED, which requires ProvisionedThroughput on the table and every GSI; PAY_PER_REQUEST rejects it
Data typesEvery attribute type; items are stored in DynamoDB’s JSON wire format, so nothing is lost to a round trip
StreamsStreamSpecification on create and update — see DynamoDB Streams
TTLUpdateTimeToLive and DescribeTimeToLive, with the asynchronous ENABLING → ENABLED and DISABLING → DISABLED lifecycle; a second update inside the transition window is rejected as AWS rejects it
MetricsSuccessfulRequestLatency, ConsumedRead/WriteCapacityUnits and UserErrors/SystemErrors are recorded to CloudWatch, transactional operations at AWS’s 2× weighting
ProtocolsAWS JSON 1.0 (X-Amz-Target: DynamoDB_20120810.<Operation>) and Smithy RPC v2 CBOR

Differences from AWS

AreaOn AWSOvercast
GSI consistencyEventually consistentImmediately consistent — an item is visible to a GSI query the instant it is written
ConsistentRead=true with an IndexNameRejectedRejected, exactly as AWS rejects it
TTL expiryExpired items are hidden on readDeleted by an hourly sweeper instead, so an expired item can still be returned
TTL status changesTake up to one hour to leave ENABLING/DISABLINGSettle after 30 seconds — long enough to be observed, short enough not to block
PartiQLExecuteStatement, ExecuteTransaction and BatchExecuteStatementOut of scope
Global tablesReplicate a table across regionsOvercast emulates one region per request; the global-table operations answer 501
Backups, exports, imports, restores, resource policies, contributor insightsFull APIAnswer 501
ThroughputProvisioned capacity is enforcedRecorded and reported; nothing is throttled

Unimplemented-but-modelled operations answer 501 Not Implemented with x-emulator-unsupported: true, in DynamoDB’s own error envelope. An X-Amz-Target naming no AWS operation at all gets 400 UnknownOperationException.

Gotchas

Important

Tables are regional. A table created in us-east-1 is invisible from eu-west-1 — ListTables omits it, DescribeTable answers ResourceNotFoundException, and the same name can exist in both regions with entirely separate items, index entries and streams. The region comes from the request: the SigV4 credential scope, a regional endpoint hostname, or OVERCAST_DEFAULT_REGION when the request names none.

UpdateTimeToLive is asynchronous and not idempotent, exactly as on AWS. The call returns while DescribeTimeToLive still reports ENABLING or DISABLING, and items only start expiring once the status reaches ENABLED. A second UpdateTimeToLive for the same table inside the transition window is a ValidationException (“Time to live has been modified multiple times within a fixed interval”), and so is re-enabling an already-ENABLED table — which is why the TTL attribute name can only be changed by disabling TTL first and enabling it again afterwards. AWS’s window is up to an hour; Overcast’s is 30 seconds, so the lifecycle is observable without a poll loop taking one.

Operations

21 of 28 listed operations are implemented. Per-operation status, notes and AWS API links: DynamoDB operations.