Skip to content

11. Global tables and backups

Two very different subjects share this chapter because they answer the same question from opposite ends: what happens when a region, or a person, does something you did not plan for?

Terminal window
aws dynamodb update-table --table-name AppData \
--replica-updates '[{"Create": {"RegionName": "us-east-1"}}]'

That is the whole setup. The table now exists in two regions, both writable, replicating to each other.

eu-west-1 us-east-1
┌──────────────┐ ┌──────────────┐
│ AppData │◄───replicate───►│ AppData │
│ writable │ │ writable │
└──────────────┘ └──────────────┘
▲ ▲
EU users write US users write
locally, ~5 ms locally, ~5 ms
replication lag: typically well under a second
WHAT YOU GET
✓ local read AND write latency in every region
✓ survives the loss of an entire region
✓ no failover procedure — the other region was
always live
✓ per-region capacity, scaled independently
WHAT IT COSTS
✗ replicated writes are billed in EVERY region
(a 3-region table = roughly 3× write cost)
✗ cross-region data transfer
✗ LAST-WRITER-WINS conflict resolution
✗ no strongly consistent reads across regions
✗ no cross-region transactions (ch 9)

Last-writer-wins, and what it really means

Section titled “Last-writer-wins, and what it really means”
t=0.000 eu-west writes status = "shipped"
t=0.050 us-east writes status = "cancelled"
t=0.400 replication settles
BOTH regions converge on "cancelled" — the write
with the later timestamp. The "shipped" write is
simply gone. No error, no conflict record, no
merge hook.
SAFE PATTERNS
• per-item region affinity: a user's data is
written only in their home region
• append-only items (distinct sort keys) instead
of mutating one shared item
• conflict-free structures: counters via ADD
still lose in LWW, so aggregate downstream
from streams instead (ch 10)
UNSAFE PATTERNS
• a global counter incremented from two regions
• a shared "current state" item written from
wherever the user happens to land
• conditional writes as a cross-region mutex —
conditions are evaluated LOCALLY

That last line deserves emphasis: a conditional write is atomic within a region. It cannot see, and cannot block, a concurrent write in another region.

YES, GLOBAL TABLES NO, ONE REGION
users on several continents one market
and latency is a product
requirement
regulatory presence in a a regional outage is
region survivable for you
whole-region failure is a you would rather
business risk you have spend the 3× write
priced cost elsewhere

Most applications do not need them, and the 3× write cost plus silent-write-loss risk is a high price for insurance against an event that has, historically, been rare and brief.

POINT-IN-TIME RECOVERY (PITR)
• continuous, automatic
• restore to ANY SECOND in the last 35 days
• restores to a NEW TABLE — never in place
• ~$0.20 per GB-month
→ turn this on for every production table, today
ON-DEMAND BACKUPS
• a full snapshot you trigger or schedule
• retained until you delete them
• no capacity consumed, no performance impact
• the answer to retention beyond 35 days and to
compliance requirements
Terminal window
aws dynamodb update-continuous-backups --table-name AppData \
--point-in-time-recovery-specification PointInTimeRecoveryEnabled=true
aws dynamodb create-backup --table-name AppData --backup-name pre-migration
aws dynamodb restore-table-to-point-in-time \
--source-table-name AppData --target-table-name AppData-restored \
--restore-date-time 2026-09-23T09:15:00Z
A RESTORED TABLE
✓ the items, as of that second
✗ auto-scaling settings — recreate them
✗ IAM policies and resource policies
✗ stream settings and their consumers
✗ TTL configuration
✗ the original table name
…and it takes MINUTES TO HOURS depending on size.

So a restore is not a failover. It is a recovery from a logical mistake — a bad deploy, a bad migration, a deletion — and the runbook has to include recreating everything in that second list and repointing the application.

Terminal window
aws dynamodb update-table --table-name AppData --deletion-protection-enabled

One flag, no cost, prevents the single most expensive human error available. Turn it on for every production table.

Terminal window
aws dynamodb export-table-to-point-in-time \
--table-arn arn:aws:dynamodb:eu-west-1:…:table/AppData \
--s3-bucket analytics-exports --export-format DYNAMODB_JSON
• requires PITR to be enabled
• consumes NO table capacity — it reads the backup,
not the table
• full or INCREMENTAL exports
• output: DynamoDB JSON or ION, in S3

This is the right answer to nearly every analytical question about DynamoDB data:

"sum revenue by month" export → Athena
"join orders with a CRM dump" export → Athena/Spark
"train a model" export → S3 → wherever
"find items matching a
complex predicate, once" export → query in S3

Running those against the live table would be a scan (chapter 4), consuming the capacity your users need. Exporting costs storage and nothing else, and the MinIO guide covers what that object storage layer is doing underneath.

CAPACITY
each replica has its own. a region receiving
replicated writes needs capacity for BOTH its
local traffic and everything the other regions
send it. under-provision one replica and
replication lag grows.
INDEXES
GSIs must exist identically in every replica.
adding one adds it everywhere, with a backfill
everywhere. (ch 7)
STREAMS
each region has its own stream. a consumer in
every region sees LOCAL and REPLICATED changes
— so naive fan-out processing runs N times for
one logical event.
THE DUPLICATE-PROCESSING TRAP
order written in eu-west
→ eu-west stream fires → send confirmation email
→ replicated to us-east
→ us-east stream fires → send it AGAIN
FIX: stamp the originating region on the item and
process only records whose region matches the
consumer's, or run the consumer in one region only.
ReplicationLatency per region pair. alarm on
sustained growth.
PendingReplicationCount records not yet applied
ConsumedCapacity per replica, separately
SCENARIO 1 — bad deploy corrupted data
→ PITR restore to the second before the deploy,
into a new table, repoint the application.
global tables do NOT help: the corruption
replicated instantly.
SCENARIO 2 — a region is unavailable
→ with global tables: route traffic elsewhere.
nothing to restore.
→ without: wait, or restore a backup into
another region (hours).
SCENARIO 3 — the table was deleted
→ deletion protection should have prevented it.
if not: restore the most recent PITR window or
on-demand backup, and recreate every setting
that a restore does not bring back.
SCENARIO 4 — a single item was corrupted
→ export or restore to a scratch table, read the
old value, write it back. the restore does not
need to become production.

Scenario 1 is the important one to internalise: multi-region protects against infrastructure, backups protect against people and code. They are not substitutes, and teams with global tables sometimes skip PITR on exactly that misunderstanding.

□ PITR enabled on every production table
□ deletion protection enabled
□ on-demand backups for anything with a retention
requirement beyond 35 days
□ table names come from configuration, not constants
□ a restore actually practised, and TIMED
□ the "what a restore does not restore" list turned
into a runbook
□ global tables: a written statement of which region
owns which items
□ exports scheduled if analytics depend on them
  • Global tables give active-active multi-region replication with local read and write latency and no failover procedure — for roughly N× the write cost plus transfer.
  • Conflict resolution is last-writer-wins with no hooks: concurrent writes to one item from two regions mean one write silently disappears.
  • Design for per-item region affinity or append-only items; never use conditional writes as a cross-region mutex, because conditions are evaluated locally.
  • No strongly consistent cross-region reads and no cross-region transactions.
  • PITR gives any second in the last 35 days, restoring to a new table; on-demand backups cover longer retention.
  • A restore does not bring back auto-scaling, IAM, streams, TTL or the table name, and it takes minutes to hours — so it is recovery from mistakes, not failover.
  • Keep table names in configuration so a restore can be adopted quickly, and enable deletion protection everywhere.
  • Export to S3 (PITR-based, consuming no table capacity) is the correct route for analytics, joins and one-off complex queries.

Next: operations and the ecosystem — IAM, encryption, DAX, local development, infrastructure as code, and the tools worth knowing.

Written by Sepuri Sai Krishna

© 2026CC BY 4.0Source