Key Takeaways

  • DynamoDB Global Tables replicate a table across multiple AWS regions automatically, giving you active-active, multi-region writes with no custom replication code.
  • Conflict resolution is last-writer-wins by timestamp at the attribute level — there's no built-in merge logic, so your application design has to account for this.
  • Global Tables require DynamoDB Streams enabled on the base table — this is what powers cross-region replication.
  • Monitor ReplicationLatency in CloudWatch; sustained high latency usually signals a hot partition or throttling in one region.
  • F9infotech designs multi-region DynamoDB architectures with conflict-aware data models, not just infrastructure replication.

Why Multi-Region DynamoDB Matters

If your application serves users across regions — say, the Middle East and Europe — single-region DynamoDB means every write from a distant region pays cross-region latency, and a regional outage takes your whole write path down. Global Tables solve both problems: each region has a full read/write replica, and AWS handles replication under the hood using DynamoDB Streams.

The tradeoff is eventual consistency across regions and the need to handle write conflicts when the same item is updated in two regions within the replication window (typically under a second, but not zero).

How Replication and Conflict Resolution Work

          Region: me-south-1              Region: eu-west-1
          ┌──────────────────┐            ┌──────────────────┐
          │   Table Replica   │  Streams   │   Table Replica   │
          │   (full R/W)      │◄──────────►│   (full R/W)      │
          └──────────────────┘            └──────────────────┘
                   │                                │
             Write: item#42                   Write: item#42
             attr=X, ts=100ms                  attr=Y, ts=102ms
                   └───────────── conflict ────────┘
                              winner: attr=Y (later timestamp)

DynamoDB resolves conflicting writes to the same attribute using the internal replication timestamp — the write with the later timestamp wins, and it propagates to all other regions. This happens automatically; you don't configure a conflict strategy. If your application needs a different resolution strategy (e.g., merge instead of overwrite), you must implement it at the application layer using versioning or vector-clock-style attributes.

Step 1: Enable DynamoDB Streams on the Base Table

Global Tables require Streams with NEW_AND_OLD_IMAGES view type.

aws dynamodb update-table \
  --table-name Orders \
  --stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES

Step 2: Create the Global Table (Version 2019.11.21)

aws dynamodb create-global-table \
  --global-table-name Orders \
  --replication-group RegionName=me-south-1 RegionName=eu-west-1 RegionName=us-east-1

For an existing table, add replicas instead:

aws dynamodb update-table \
  --table-name Orders \
  --replica-updates '[
    {"Create": {"RegionName": "eu-west-1"}},
    {"Create": {"RegionName": "us-east-1"}}
  ]'

Step 3: Terraform for Repeatable Deployment

resource "aws_dynamodb_table" "orders" {
  name             = "Orders"
  billing_mode     = "PAY_PER_REQUEST"
  hash_key         = "OrderId"
  stream_enabled   = true
  stream_view_type = "NEW_AND_OLD_IMAGES"

  attribute {
    name = "OrderId"
    type = "S"
  }

  replica {
    region_name = "eu-west-1"
  }

  replica {
    region_name = "us-east-1"
  }
}

Apply this from a single region — Terraform's aws_dynamodb_table resource with multiple replica blocks provisions the global table in one pass.

Step 4: Designing Your Data Model to Survive Last-Writer-Wins

Because resolution is attribute-level and timestamp-based, structure write-heavy fields so concurrent updates don't silently clobber each other:

import boto3
from datetime import datetime, timezone

dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table("Orders")

def update_order_status(order_id, new_status, region_tag):
    table.update_item(
        Key={"OrderId": order_id},
        UpdateExpression="SET #s = :status, LastUpdatedRegion = :region, UpdatedAt = :ts",
        ExpressionAttributeNames={"#s": "Status"},
        ExpressionAttributeValues={
            ":status": new_status,
            ":region": region_tag,
            ":ts": datetime.now(timezone.utc).isoformat(),
        },
    )

Storing LastUpdatedRegion and UpdatedAt explicitly lets you audit which region "won" a conflict after the fact, even though DynamoDB itself doesn't surface a conflict event to your application.

Step 5: Monitor Replication Health

Set a CloudWatch alarm on replication latency per region — this is your early warning for a struggling replica.

aws cloudwatch put-metric-alarm \
  --alarm-name "Orders-ReplicationLatency-euwest1" \
  --namespace AWS/DynamoDB \
  --metric-name ReplicationLatency \
  --dimensions Name=TableName,Value=Orders Name=ReceivingRegion,Value=eu-west-1 \
  --statistic Average \
  --period 60 \
  --threshold 1000 \
  --comparison-operator GreaterThanThreshold \
  --evaluation-periods 3 \
  --alarm-actions arn:aws:sns:me-south-1:123456789012:dynamodb-alerts

Cost and Capacity Notes

Every write is replicated to every other region — meaning a write to a 3-region global table consumes write capacity in all three regions, not just the one it originated in. Factor this 3x write multiplier into your capacity planning and cost estimates before enabling additional regions.

1 write (origin) Replica A Replica B Replica C

FAQ

Can I use Global Tables with provisioned capacity instead of on-demand? Yes, but you must configure auto-scaling consistently across all replicas, since each replica consumes its own regional capacity for every replicated write.

What happens if one region goes down? Writes continue in the healthy regions. When the failed region recovers, DynamoDB catches up replication automatically — no manual resync is required.

Does Global Tables support transactions (TransactWriteItems) across regions? Transactions are scoped to a single region/table; cross-region consistency for multi-item operations must be handled at the application layer.

Is there a conflict-free alternative to last-writer-wins? Not natively. For CRDT-style merge semantics, you'd implement custom logic using DynamoDB Streams to detect and reconcile conflicting writes in near real time.

Build a Resilient Multi-Region Data Layer

F9infotech designs DynamoDB Global Table architectures with conflict-aware data models and tested failover — not just infrastructure replication. Talk to our team about your multi-region data strategy.