General trade-offs
First establish where the data must run. Then compare the DynamoDB adapters available in that environment. An adapter includes both the DynamoDB origin and a particular target service; a larger backend does not supply an operation outside that mapping’s contract. The DynamoDB service catalog gives operation-level coverage. The sections below separate workload choices within each environment from the general requirements that apply to all of them.Application requirements
Before choosing, answer these questions:- Which requests need atomic changes across several items or tables?
- Which GSI/LSI queries, sort orders and filters does the application actually use?
- Must numeric values preserve DynamoDB’s full decimal precision?
- Does another component consume DynamoDB Streams or depend on per-item TTL?
- Are keys distributed, or does most traffic contend on a few items?
- Who else shares the database, cluster, connection budget and recovery procedure?
Who operates the chosen architecture?
For these examples, your platform team operates Cloud Adapter and target account; your application team owns business correctness. These assignments do not imply a Tensor9 managed-operations service.
Two logical tables can share one physical capacity or failure boundary. Do not assume separate names mean independent instances. Consult configuration for pre-provisioned bindings and operations for the deployment’s operating procedures.
Google Cloud
Firestore, Cloud SQL PostgreSQL, Spanner and Bigtable
These four mappings offer different numeric, transaction, indexing and capacity models in the same target environment. Compare candidates against the same item values, request mix and recovery requirements.Tenant metadata with quiet periods
Consider a tenant directory in Google Cloud: small records, point reads by tenant ID, lookup by email and conditional profile updates. Nights are quiet. The application uses ordinary counts and timestamps, not arbitrary-precision financial values. Compare DynamoDB → Firestore with DynamoDB → Cloud SQL PostgreSQL. In the Firestore mapping, Cloud Adapter stores typed documents and uses maintained composite indexes for secondary lookups, rather than scanning every document to answer an indexed query. The PostgreSQL mapping uses typed item storage and native indexes. Both retain the application’s DynamoDB calls within their documented contracts. Cloud SQL commits provisioned database capacity even during quiet periods; that capacity can also serve a sustained or shared workload. Firestore’s request and index work instead matters to the comparison. A conditional update may read the document, evaluate the condition and retry after a competing write. Include that work, idle capacity, storage and operating effort in both budgets. Firestore also supports cross-document transactions; needing more than one item does not automatically eliminate it. Numeric representation is a separate question. Values outside Firestore’s accepted numeric range exclude that mapping for requests requiring those exact values; PostgreSQL preserves the documented DynamoDB decimal domain. Compare the actual values, transaction contention and traffic duty cycle rather than inferring a cost result from either storage model. Comparison record: Google Cloud; intermittent metadata; Firestore request/index work and document contention versus Cloud SQL provisioned capacity, connections and transaction contention. The application team owns index rollout and retry behavior; the platform team owns access, budgets and recovery for either option. Test actual update shapes and both key lookups on each candidate, retaining cost and correctness observations separately. For migration, copy a representative tenant and account for writes during the copy before moving traffic.Orders, inventory and exact amounts
A regional order service updates an order and its inventory record together. A failed condition must leave both unchanged. Amounts must retain their decimal value. DynamoDB Streams is not required for this transaction path. Compare DynamoDB → Cloud SQL PostgreSQL with DynamoDB → Spanner. On PostgreSQL, Cloud Adapter evaluates the conditions and commits the item changes inside one serializable database transaction. The application still sendsTransactWriteItems; it does not become a SQL application.
PostgreSQL’s instance capacity, storage and connections are shared budgets. Contention can produce retryable transaction conflicts, so test hot stock records, not only unrelated orders. The PostgreSQL pool guidance explains why adding adapter processes without budgeting their connections can make matters worse.
Spanner preserves exact DynamoDB numeric values and implements cross-table transactions and native secondary indexes, with provisioned capacity and a replicated commit path. Compare its transaction placement and capacity model with PostgreSQL’s instance, lock and connection boundaries using the same transaction mix and deployment locality; single-item throughput does not predict transaction latency.
The PostgreSQL transaction contract examined here excludes stream-enabled tables. Spanner’s mapping also does not serve DynamoDB Streams. If transactions and change capture are both hard requirements, neither described path satisfies that combination; examine the documented combined contract of other mappings.
Comparison record: Google Cloud; exact-value order transactions; Cloud SQL instance/connection/lock budgets versus Spanner provisioned capacity and replicated transactions. The platform team owns database capacity and recovery, and the application team owns contention handling and acceptance tests for either candidate. The check below illustrates the transaction assertions on Cloud SQL; repeat the same assertions through the configured Spanner adapter to compare observations. Migration must preserve exact values and catch up writes before cutover; keeping the old database does not undo new target writes.
Independent key-value records
A device-state service stores independent records under widely distributed keys. It reads by primary key, mostly writes unconditionally and needs neither secondary indexes, cross-item transactions, Streams nor per-item TTL. Compare DynamoDB → Bigtable with DynamoDB → Spanner. Bigtable’s row-local mapping stores one item per row, and eligible writes avoid fetching its previous contents. Conditions and more complex updates use a guarded read-modify-write path. Spanner stores items in native tables with a transaction and secondary-index model. Bigtable requires provisioned cluster capacity and exposes the narrower API contract described above. Adding nodes does not split a single hot item. Measure real item sizes, skew and conditional writes alongside the uniform-key case. The Bigtable mapping also relaxes the aggregate item-size check for eligible blind updates; it does not suit applications that depend on that exact rejection behavior. Secondary-key queries or atomic multi-item changes are supported by the described Spanner mapping but excluded from the Bigtable mapping. Those are contract differences, not settings that a larger Bigtable instance can supply. If Streams becomes required, consult another qualifying profile rather than assuming Spanner supplies it. Comparison record: Google Cloud; independent base-key records; Bigtable row-local mutation and cluster capacity versus Spanner transactions, indexes and instance capacity. Measure each with the same key skew and conditional-update mix. For Bigtable, prepare the physical table, column families and verified single-cluster application profile before serving logical tables. For Spanner, verify the configured schema and indexes. Load and compare records before cutover; neither described mapping supplies a Streams-based catch-up path.Try the Cloud SQL transaction path
This disposable check demonstrates a rejected transaction, an accepted transaction and an identical retry against an installed test endpoint. Cloud SQL is the concrete test fixture, not a backend recommendation. It is a client-side check, not a backend installation procedure or production load test. The backend is a real Google Cloud database.1
Confirm the installed mapping and its contract
Ask the deployment owner for an isolated endpoint whose table-creation path selects Use origin credentials authorized at your adapter endpoint; Google Cloud backend credentials belong to the adapter.This inspects the directed profile without executing a cloud request.
google::1.0.0::cloudsql::postgresql, the origin credential profile and region accepted there, and permission to create and delete disposable tables. The owner must have prepared the Cloud SQL database, its connection binding, runtime identity and durable adapter state. Confirm the effective mapping with that owner; a profile lookup does not identify a running endpoint’s backend.Install the Tensor9 CLI, and have the AWS CLI and Python with boto3 available:2
Set the test client's endpoint
Set the installed test endpoint and the origin authentication settings supplied by its owner:The service-specific variable routes DynamoDB clients in this process. With it set,
boto3.client("dynamodb", region_name=os.environ["AWS_REGION"]) uses that endpoint. To scope the choice to one client, pass it explicitly instead, as the script below does. Other AWS service clients remain unchanged.3
Check access before creating data
Run one bounded, read-only catalog request:Expect a DynamoDB response containing a
TableNames list, which can be empty. This checks endpoint reachability, origin authorization and access to the adapter’s table catalog. It does not prove native database write access or transaction readiness. If it fails, resolve the endpoint, identity or catalog error before proceeding. The next step’s table creation, waiter and item writes exercise the selected backend before the transaction assertions.4
Run the complete transaction check
Save this as Repeat the identical request promptly. DynamoDB’s request-token contract provides a ten-minute idempotency window; changing parameters while reusing the token is a different test.
check-dynamodb-tradeoffs.py, replace the endpoint with your installed test endpoint, then run python check-dynamodb-tradeoffs.py. It creates tradeoffs-orders with Streams disabled and leaves it available for inspection. Use an isolated test environment where that table does not already exist. If creation reports that it exists, stop; do not reuse or delete someone else’s table.5
Interpret the observations
Expected observations, not captured benchmark output:
- The false condition rejects the transaction; order and stock remain unchanged.
- The valid transaction changes both items, preserving the exact amount.
- The immediate identical retry leaves stock at zero and the order paid.
x-t9-explain: true executes a request, so do not replay mutations just to collect a report.After this check, qualify contention and recovery with representative data, including ambiguous network failures, adapter restart and database failover. The sequential reads above do not prove isolation for concurrent readers.6
Clean up only the experiment
Confirm the endpoint still points at the installed test adapter and that this run created Keep evidence before deletion if a check failed. Do not stop a shared adapter or remove its database. Deleting this logical table does not retire the Cloud SQL instance or stop its charges; let the infrastructure owner remove any dedicated test database, backups or instance when no other test depends on them.
tradeoffs-orders, then inspect and delete that table:Microsoft Azure
Cosmos DB options and workload fit
Neither option supplies the full DynamoDB multi-item transaction contract. Reject a mapping if required numeric values, transaction shapes or indexes fall outside its profile before comparing its cost. A quiet workload alone does not determine the choice.
Azure: provisioned or serverless Cosmos DB?
Consider a nontransactional tenant directory in Azure: point reads, conditional single-item updates and quiet nights. Compareazure::1.0.0::cosmosdb::serverless with azure::1.0.0::cosmosdb::provisioned using the same traffic trace and item sizes.
The provisioned Cosmos DB mapping provides a managed DynamoDB GSI path; the serverless mapping does not. A required GSI therefore excludes serverless for that workload. For supported base-table/LSI operations, compare serverless consumption with provisioned capacity using the same duty cycle. Neither throughput mode alone establishes a multi-item transaction contract.
Provisioned capacity buys an explicit RU budget, not immunity to partition heat. Compare conditional-update work, index amplification and demand across partition keys. A hot partition can throttle while other capacity is idle. Serverless consumption also has capacity limits; measure bursts and completed work, not only the quiet-period bill.
Comparison record: Azure placement; provisioned RU allocation and managed GSI behavior versus serverless consumption and its supported base-table/LSI contract. Record any excluded operations before comparing capacity, partition heat and total cost. The platform team owns account mode, container capacity and alerts for either deployment. Account mode is distinct from a table’s throughput allocation: logical tables sharing a container share its budget. DynamoDB BillingMode does not switch the Cosmos account mode, and a backend tag does not migrate data. Changing modes requires a documented account/container migration and cutback procedure, including index rebuild and writes accepted after cutover. Continue with the Cosmos comparison and capacity examples.
Scaleway
Managed PostgreSQL or CloudNativePG
The catalog offers Scaleway Managed Database for PostgreSQL and CloudNativePG. Both use PostgreSQL-backed DynamoDB item storage. The choice concerns where the database runs and who maintains its infrastructure, alongside the supported transaction, index and Streams combinations.
For an order service requiring exact amounts and atomic changes, run the transaction assertions from the Google Cloud example through the Scaleway endpoint whose selected mapping documents that contract. For a stream consumer, separately verify the profile’s stream-writer restrictions and recovery behavior. A managed host and a cluster-local host are not interchangeable backup plans.