This page requires JavaScript to display.
D
Unpacking...
← Cloud Platforms
Cloud Platforms

Amazon DynamoDB for Data Engineers

Keys and capacity, access-pattern modelling, boto3 examples (conditional writes, queries, watermarks), streams and exports, transactions, TTL, backups and cost.

Contents
1. DynamoDB Concepts 2. Data Modelling: Access Patterns First 3. Working with DynamoDB in Python 4. Streams, Exports & Analytics 5. Transactions, TTL, Backups & Cost 6. Common Interview Questions

1. DynamoDB Concepts

Amazon DynamoDB is a serverless key-value and document database with single-digit millisecond latency at any scale. Data engineers use it as a source (application data, exported to the lake) and as pipeline infrastructure: watermarks, idempotency keys, job state, configuration and online feature serving.

ConceptDetail
Table / item / attributeSchemaless items (max 400 KB each) identified by a primary key
Partition key (PK)Hashed to choose the storage partition; must spread load evenly
Sort key (SK)Optional; orders items within a partition and enables range queries (begins_with, between)
Capacity modesOn-demand (pay per request, no planning) or provisioned RCU/WCU with auto scaling (cheaper for steady load)
ConsistencyEventually consistent reads by default; strongly consistent reads optional (on the base table)
Secondary indexesGSI: different PK/SK, own capacity, eventually consistent. LSI: same PK, different SK, defined at table creation

2. Data Modelling: Access Patterns First

DynamoDB has no joins and no ad-hoc queries: design keys from the questions the application asks. A common approach is single-table design, storing related entities together so one query returns them:

PKSKAttributesServes
ACCOUNT#A1PROFILEname, tier, cityGet account profile
ACCOUNT#A1TXN#2026-10-26T10:15:00#T9amount, channelLatest transactions for an account (SK range)
ACCOUNT#A1ALERT#2026-10-26#R7rule, statusOpen alerts for an account
PIPELINE#daily_txnWATERMARKlast_ts, updated_atIncremental pipeline state

3. Working with DynamoDB in Python

import boto3
from boto3.dynamodb.conditions import Key
from botocore.exceptions import ClientError

table = boto3.resource("dynamodb").Table("fraud-app")

# idempotent insert: only if this key does not exist yet
try:
    table.put_item(
        Item={"PK": "ACCOUNT#A1", "SK": "TXN#2026-10-26T10:15:00#T9", "amount": 2500, "channel": "UPI"},
        ConditionExpression="attribute_not_exists(PK)",
    )
except ClientError as e:
    if e.response["Error"]["Code"] != "ConditionalCheckFailedException":
        raise  # anything else is a real error; duplicate is fine

# query: last 20 transactions for an account, newest first
resp = table.query(
    KeyConditionExpression=Key("PK").eq("ACCOUNT#A1") & Key("SK").begins_with("TXN#"),
    ScanIndexForward=False, Limit=20)
items = resp["Items"]

# atomic counter / update
table.update_item(
    Key={"PK": "ACCOUNT#A1", "SK": "PROFILE"},
    UpdateExpression="SET txn_count = if_not_exists(txn_count, :zero) + :one, last_seen = :ts",
    ExpressionAttributeValues={":zero": 0, ":one": 1, ":ts": "2026-10-26T10:15:00Z"})

# bulk writes (handles batching and retries of unprocessed items)
with table.batch_writer() as batch:
    for row in rows:
        batch.put_item(Item=row)
# pipeline watermark table: read, process, then advance only if nobody else did
state = boto3.resource("dynamodb").Table("pipeline-state")
current = state.get_item(Key={"pipeline": "daily_txn"}, ConsistentRead=True).get("Item", {})
old_wm = current.get("watermark", "1970-01-01T00:00:00Z")
new_wm = run_incremental_load(since=old_wm)
state.update_item(
    Key={"pipeline": "daily_txn"},
    UpdateExpression="SET watermark = :new",
    ConditionExpression="attribute_not_exists(watermark) OR watermark = :old",  # optimistic lock
    ExpressionAttributeValues={":new": new_wm, ":old": old_wm})

Avoid Scan in application paths: it reads the whole table. Paginate with LastEvaluatedKey when you must scan (e.g. small admin tasks).

4. Streams, Exports & Analytics

FeatureUse
DynamoDB StreamsOrdered per-item change log (24 h retention) consumed by Lambda: triggers, aggregations, replication
Kinesis Data Streams for DynamoDBChanges into a Kinesis stream for longer retention and more consumers (Firehose → S3)
Export to S3Full or incremental exports from point-in-time recovery data, in DynamoDB JSON or Ion, without consuming table capacity
Zero-ETL integrationsReplicate into Redshift or OpenSearch for analytics and search
Import from S3Create a new table from CSV/JSON/Ion files in S3
aws dynamodb export-table-to-point-in-time \
  --table-arn arn:aws:dynamodb:ap-south-1:111122223333:table/fraud-app \
  --s3-bucket acme-lake-prod --s3-prefix raw/dynamodb/fraud-app/ \
  --export-format DYNAMODB_JSON \
  --export-type INCREMENTAL_EXPORT \
  --incremental-export-specification "ExportFromTime=2026-10-25T00:00:00Z,ExportToTime=2026-10-26T00:00:00Z,ExportViewType=NEW_AND_OLD_IMAGES"

5. Transactions, TTL, Backups & Cost

6. Common Interview Questions

QuestionShort answer
How do you choose a partition key?High cardinality, evenly distributed access, and present in your main access patterns, avoiding hot keys
GSI vs LSI?GSI: any partition and sort key, own capacity, created any time, eventually consistent. LSI: same partition key, different sort key, created with the table, strongly consistent reads possible
On-demand vs provisioned?On-demand: pay per request, no planning, good for spiky or new workloads. Provisioned + auto scaling: cheaper for steady traffic
How do you get DynamoDB data into the lake?Incremental exports to S3, DynamoDB Streams or Kinesis → Firehose → S3, or zero-ETL to Redshift
How do you make writes idempotent?Conditional writes such as attribute_not_exists on the key, or a version attribute for optimistic locking
Why is Scan discouraged?It reads every item (expensive, slow, consumes capacity); design keys and indexes so Query serves access patterns