DynamoDB
Tables, items, transactions, PartiQL, backups, global tables, streams, TTL.
fakecloud implements 57 of 57 DynamoDB operations at 100% Smithy conformance.
Regions
Tables are regional. The same table name can exist independently in every region of an account, and ListTables, DescribeTable and every table-addressed call see only the tables of the region the request is signed for; a table, stream, backup, export or import ARN naming another region is not found. Backups, exports, imports, streams and resource policies live in the region of their table. DynamoDB Streams consumers (Lambda event source mappings, EventBridge Pipes), Step Functions DynamoDB tasks (real DynamoDB calls in the execution's account and region) and CloudFormation-provisioned tables resolve each table in the region its ARN, execution or stack names.
Multi-region tables follow AWS's two global-table versions:
- Version 2019.11.21:
UpdateTablewithReplicaUpdatesCreatebuilds a replica table in the target region (same schema, indexes, billing, stream, TTL and encryption settings, and the current rows; its own ARN, stream ARN, tags and policy). It is an ordinary table of that region,DescribeTableon any member lists the others underReplicaswithGlobalTableVersion2019.11.21, andDeleteremoves the replica table. Deleting a member table drops it from the set. - Version 2017.11.29:
CreateGlobalTableover same-named tables in several regions; the global table is describable and updatable from any region of its replication group, andListGlobalTableshonorsRegionName.
Item writes (single-item, batch, transaction, PartiQL, Step Functions DynamoDB tasks and TTL expiry) to any member replicate synchronously to the others: exactly the rows a write touched are copied, the last write to a row wins, and each replicated change is recorded on the receiving replica's stream. For version 2019.11.21 tables, billing mode and capacity, attribute definitions, global secondary indexes, the stream specification and the TTL setting are kept in step across replicas (UpdateTable or UpdateTimeToLive on any member); table class, encryption key, deletion protection, tags and resource policy stay per replica. CreateGlobalTable does not verify that the member tables exist or are empty.
Supported features
- Tables — CRUD, attributes, indexes (GSI, LSI), billing modes, tags, resource-based policies on tables and streams (
PutResourcePolicy/GetResourcePolicy/DeleteResourcePolicywithExpectedRevisionId,CreateTableResourcePolicy) - Items — GetItem, PutItem, UpdateItem, DeleteItem, BatchGetItem, BatchWriteItem
- Transactions — TransactGetItems, TransactWriteItems with conditional checks
- Query and Scan — full expression support (key conditions, filter expressions)
- PartiQL — ExecuteStatement, BatchExecuteStatement, ExecuteTransaction;
SELECT ... FROM "table"."index"reads the index (rows carrying its key, with its projected attributes) - Update expressions — SET, REMOVE, ADD, DELETE with function support (
size,attribute_exists,begins_with,contains,attribute_type) - Condition expressions — full operator support with correct type coercion
- Global tables — replica management, replica status reporting
- Backups — CreateBackup, DescribeBackup, RestoreTableFromBackup
- Streams — shard iterators, record retrieval, delivery to Lambda/Kinesis
- TTL — expire items via
/_fakecloud/dynamodb/ttl-processor/tick - Exports and imports: background jobs that report
IN_PROGRESS -> COMPLETED/FAILED.ExportTableToPointInTimewrites the AWS export layout (AWSDynamoDB/<id>/withmanifest-summary.json,manifest-files.jsonand gzipdata/*.json.gzor*.ion.gz) in DynamoDB JSON or Ion. Every object an export writes is encrypted as itsS3SseAlgorithmasks (AES256, orKMSunderS3SseKmsKeyId, else the AWS-managedaws/s3key), overriding the bucket's default encryption; an export that names no algorithm takes the bucket default. With point-in-time recovery enabled the table's writes are recorded, so a full export at a pastExportTimereflects the table at that moment andINCREMENTAL_EXPORTwrites oneKeys/OldImage/NewImagerecord per item changed in[ExportFromTime, ExportToTime)(15 minutes to 24 hours,NEW_IMAGEorNEW_AND_OLD_IMAGES). Deliberate deviation: export time problems (point-in-time recovery not enabled, a futureExportTime, or a window outside the retained history or the 15-minute to 24-hour range) are accepted by the call and reported as aFAILEDexport withFailureCodePointInTimeRecoveryUnavailableExceptionorInvalidExportTimeException, where AWS rejects the call synchronously.ImportTablecreates the table asCREATING, reads DynamoDB JSON, Ion or CSV objects withInputCompressionTypeGZIP, ZSTD or NONE, applies theTableCreationParameters(billing mode, throughput, GSIs, SSE), and flips the tableACTIVE; a table exported here re-imports to identical items - ConsumedCapacity + ItemCollectionMetrics — every data-plane op (
GetItem,PutItem,UpdateItem,DeleteItem,Query,Scan,BatchGetItem,BatchWriteItem,TransactGetItems,TransactWriteItems, PartiQL variants) returnsConsumedCapacitywhen the caller requests it viaReturnConsumedCapacity = TOTAL/INDEXES. Capacity units are synthesized from the serialized item byte size using AWS's documented 4 KB read / 1 KB write rounding, broken out per table + per index.ItemCollectionMetricsis emitted on writes touching tables that have a local secondary index, withSizeEstimateRangeGBrounded to the AWS-documented[lower, upper]shape - IAM enforcement — with
FAKECLOUD_IAM=strict(orsoft), every DynamoDB and DynamoDB Streams operation is authorized against the caller's policies using the actions and resource ARNs AWS uses: the table, index, stream, backup, export or import ARN; the batch action on every table in a batch; the per-item action on each table in a transaction;PartiQLSelect/PartiQLInsert/PartiQLUpdate/PartiQLDeletefor PartiQL;aws:ResourceTag/aws:RequestTag/aws:TagKeysconditions on table tags; fine-grained access control throughdynamodb:LeadingKeys,dynamodb:Attributes,dynamodb:Select,dynamodb:ReturnValues,dynamodb:ReturnConsumedCapacity,dynamodb:EnclosingOperationanddynamodb:FullTableScan; and table and stream resource-based policies, whose explicit Deny wins and whose Allow grants same-account principals on its own. See SigV4 verification and IAM enforcement TableNameaccepts ARNs, including other accounts' tables: every operation that takes aTableName(orResourceArn,StreamArn) also accepts the fullarn:aws:dynamodb:<region>:<account>:table/<name>form. An ARN naming another account reaches that account's table for the operations AWS supports cross-account:GetItem,PutItem,UpdateItem,DeleteItem,Query,Scan,BatchGetItem,BatchWriteItem,TransactGetItems,TransactWriteItems(a batch or transaction can mix tables from several accounts, and a transaction stays atomic across them),DescribeTable,UpdateTable,DeleteTable,ListTagsOfResource,TagResource,UntagResource, and the StreamsDescribeStream,GetShardIteratorandGetRecords. With IAM enforcement on, such a request needs both the caller's identity policy and the table's (or stream's) resource-based policy. Any other operation (PartiQL, backups, point-in-time recovery, TTL, Kinesis streaming, resource-policy operations, imports and exports) does not find another account's table, and an ARN naming a region other than the request's is not found for any operation- Service Quotas enforcement (opt-in): with "Maximum number of tables" (
L-F98FE922) enforced in Service Quotas,CreateTable,RestoreTableFromBackup,RestoreTableToPointInTime,ImportTableand a new replica inUpdateTableare refused past the region's applied value withLimitExceededException. Off by default
Protocol
JSON protocol. X-Amz-Target header, JSON body, JSON responses.
Introspection
POST /_fakecloud/dynamodb/ttl-processor/tick— expire items whose TTL attribute is in the pastPOST /_fakecloud/dynamodb/snapshot/save— write the current DynamoDB state as a canonical snapshot on demand. An optional JSON body{"dataPath": "<dir>"}writes to<dir>/dynamodb/snapshot.json; with no body it writes to the configured persistent store. Returns{"saved": true},400when neither a store nordataPathis available, and500on write failure. Lets import/export tooling populate DynamoDB through the normal API and then have fakecloud emit the canonical snapshot format instead of reproducing snapshot internals out of tree.
Importing an AWS export at startup
Seed one or many local tables from real DynamoDB S3 exports, bulk-loaded directly into the store before the server starts serving. Single-table and multi-table each use their own flag — the two are mutually exclusive (startup aborts if both are set).
Single-table mode
--dynamodb-import-path(FAKECLOUD_DYNAMODB_IMPORT_PATH) — the localAWSDynamoDB/<export-id>/folder that holdsmanifest-summary.json(as produced by an AWS DynamoDB S3 export).--dynamodb-import-describe-table(FAKECLOUD_DYNAMODB_DESCRIBE_TABLE) — anaws dynamodb describe-tableJSON dump supplying the table shape (key schema, attribute definitions, indexes, billing mode).
Both are required together.
fakecloud \
--dynamodb-import-path ./AWSDynamoDB/01234567890123-abcdef01 \
--dynamodb-import-describe-table ./describe-table.jsonMulti-table mode
--dynamodb-import-dir(FAKECLOUD_DYNAMODB_IMPORT_DIR) — a root directory of per-table subdirectories, each self-contained with its owndescribe-table.jsonalongside that table'smanifest-summary.json/manifest-files.json/data/*.json.gz. Subdirectory names carry no meaning — each table's name comes from its owndescribe-table.json.
root/
Music/
describe-table.json
manifest-summary.json
manifest-files.json
data/0001.json.gz
Orders/
describe-table.json
manifest-summary.json
manifest-files.json
data/0001.json.gzfakecloud --dynamodb-import-dir ./rootEvery subdirectory is imported using the same rules as single-table mode.
Constraints (both modes)
--dynamodb-import-describe-tablealone, without--dynamodb-import-path, aborts startup — it has nothing to pair with.--dynamodb-import-path/--dynamodb-import-describe-tableand--dynamodb-import-dirare mutually exclusive — passing both aborts startup before any import runs.- Idempotent, per table. Each import creates a new table. If a table of that name already exists, that table's import is skipped with a warning and its existing data is left untouched (no merge, no append, no overwrite). This makes restarting with the flags still set safe.
- Additive: tables are materialised straight in the store. They do not go through
BatchWriteItemand do not touch the modeledImportTableAPI operation. - Targets the default (single) account named by
--account-idin the configured region. - Only the AWS
DYNAMODB_JSONexport format is supported (manifests plus gzippeddata/*.json.gzfiles); ION and CSV are not. - Every imported item must carry the key attributes declared in its describe-table
KeySchemawith the type declared inAttributeDefinitions(the same presence and type checks the normal write path enforces). If a table's manifests declare anitemCountthat disagrees with the data actually read, the whole import is rejected as truncated or corrupt. Any bad or unreadable input — including a multi-table root with no subdirectories, or a subdirectory missing itsdescribe-table.json— aborts startup loudly before any table is written to state. - Works in either storage mode. Under
--storage-mode=persistentimported tables are persisted like any other state (written once after the whole batch, not per table), so on a later restart they're already present and skipped (see the idempotent behavior above) rather than re-imported.
Cross-service delivery
- DynamoDB Streams -> Lambda — Event source mapping polls and invokes
- DynamoDB -> Kinesis — Table changes stream to Kinesis Data Streams