Supported environments
- Akamai
- Azure
- DigitalOcean
- Google Cloud
- OCI
- Private Kubernetes
- Scaleway
How the targets compare
Each row compares a capability of DynamoDB with its adaptation on each target. A dash means this profile does not state the capability for that target.Cloud Adapter
On Akamai, DigitalOcean, Private Kubernetes, and Scaleway
PostgreSQL
PostgreSQL in the Cloud Adapter deployment
Tensor9 deploys and operates the PostgreSQL store with the customer Cloud Adapter deployment, including disconnected deployments. Application requests use the same Rust DynamoDB-to-PostgreSQL implementation as the managed PostgreSQL target. Database access uses the configured connection credentials; Cloud SQL IAM authentication is specific to the Google-managed target. The customer supplies the infrastructure, and the deployment’s storage, backup and recovery configuration determines availability.How it works
Tensor9 runs a DynamoDB adapter beside your application in the customer’s environment. It configuresAWS_ENDPOINT_URL_DYNAMODB to send the AWS SDK’s requests to the adapter over the local loopback network. Your SDK and application code stay unchanged. The adapter accepts DynamoDB requests and data types, returns DynamoDB responses and errors, and stores data in PostgreSQL.
DynamoDB supports numbers with up to 38 significant digits, typed sets, conditional writes, secondary indexes, and atomic transactions. The adapter implements these using PostgreSQL storage and transactions. PostgreSQL supports multi-table transactions and synchronously updated indexes, but has different concurrency, capacity, and identifier limits. Unsupported requests return errors; the limitations below describe the differences.
For base-table Query and Scan requests, the adapter compiles supported filters into parameterized SQL WHERE predicates over the JSONB item. Number comparisons cast stored decimal text to PostgreSQL numeric. An order-preserving key column supplies sort bounds, cursor position, and direction. The query uses a server-side cursor to fetch bounded batches until the requested Limit or 1 MiB of item data. Expressions that cannot be represented in SQL are evaluated in the adapter over the rows selected by the SQL predicate. Secondary-index queries use the separate path described below.
For conditional writes, the adapter opens a transaction, locks the row with SELECT ... FOR UPDATE, evaluates the ConditionExpression, and writes within that transaction. This requires an extra round trip, but prevents a concurrent writer from changing the item between the check and write. A failed condition returns ConditionalCheckFailed and can return the item that failed it. Some unconditional writes skip the read: a top-level SET/REMOVE patch or integral counter add uses one statement when it has no condition, requests no returned item image, and affects no secondary index or stream.
Your application uses the DynamoDB API through an adapter in the target environment.
Architecture
The adapter is a stateless Rust service. It parses DynamoDB expressions, translates requests into PostgreSQL operations, and returns DynamoDB responses. It connects to PostgreSQL through a connection pool using the customer’s credentials. Durable state stays in PostgreSQL, so adapter instances can restart or scale out without coordinating local state. Stream-enabled tables have the separate single-writer restriction below. Each DynamoDB table has a PostgreSQL table namedddb_<name> in one database. The ddb_tables registry records its generated physical name, key schema, billing mode, time-to-live (TTL) settings, global secondary indexes (GSIs), and stream settings. A write or query for a table absent from the registry returns ResourceNotFoundException; writes do not create tables implicitly. At runtime, CreateTable creates a PostgreSQL expression index for each declared GSI. Each stream-enabled table also has a _strm table that stores change records.
A stateless Rust adapter serves the DynamoDB API in front of Postgres; all durable state lives in one Postgres database, where each DynamoDB table is its own physical relation.
The adapter first builds a storage-independent request plan, then converts it to a Postgres-specific plan for execution.
Schemas
A DynamoDB item occupies one PostgreSQL row with columnspk TEXT, sk TEXT, okey TEXT and item JSONB. The PRIMARY KEY (pk, sk) index serves GetItem. A separate index over pk and bytewise-collated okey serves ordered base-table Query requests.
The item JSONB column preserves DynamoDB’s typed attribute representation, including {"N":"123.45"}, {"B":"<b64>"}, and typed sets. Numbers remain decimal strings, so a 38-digit amount or a Snowflake ID is not rounded through a floating-point conversion. Type tags preserve the distinction between numbers and numeric strings. Conditional writes use row locks, not a separate version column. Enabling TTL builds an expression index over the configured epoch attribute inside the JSONB item. A bounded, leader-elected reaper deletes eligible rows through that index. Expired items remain readable until physical deletion; reads do not filter on TTL.
Each attribute keeps its DynamoDB type tag inside item JSONB , so {“N”:“123.45”} keeps its exact decimal string.
Where tables live
Each DynamoDB table has its own PostgreSQL table, indexes and optional_strm change-record table. CreateTable creates those database objects and their registry entry; DeleteTable drops them. Storage, indexes and vacuum settings can be tuned per table.
The adapter checks a 500-table guardrail per namespace when creating a physical DynamoDB table. Concurrent creates of different tables can exceed that guardrail; it is not a hard PostgreSQL quota. Plan database capacity and table placement for larger deployments. Provisioned instances continue to incur compute costs while idle.
Each declared table is its own physical relation. CreateTable and DeleteTable create and drop PostgreSQL relations. The adapter applies a 500-table guardrail per namespace.
Conditional writes
To evaluate a conditional write, the adapter locks the item’s(pk, sk) row with SELECT … FOR UPDATE, checks the ConditionExpression against that row, then writes and commits. The lock prevents another writer from changing the item between the check and write.
A false condition returns the non-retryable ConditionalCheckFailed error. A PostgreSQL serialization failure or lock timeout (40001/lock-not-available) instead returns a retryable throughput error, allowing the SDK to back off and retry. Concurrency failures are not reported as failed conditions.
For attribute_not_exists(pk), the PostgreSQL primary-key constraint prevents two concurrent requests from creating the same item. Only one insert can succeed for a given (pk, sk).
Failed conditions and PostgreSQL concurrency conflicts return different error types.
Secondary indexes
On each write, the adapter adds two index fields to the item’s JSONB. The partition-key field,_idx_<name>_h, normalizes equivalent values such as 1 and 1.0. The sort-key field, _idx_<name>_o, preserves sort order and uses the base key to break ties. A PostgreSQL expression index over these fields locates matching partition keys. The adapter then evaluates sort-key conditions, ordering, pagination, and any FilterExpression over the retrieved items.
The index fields and item commit in the same transaction, so GSI queries are strongly consistent. DynamoDB’s own GSIs update asynchronously and are eventually consistent. Each index lookup is limited to 10,000 candidate items for one index partition-key value. Exceeding this limit returns an error; choose index keys with this limit in mind.
A GSI uses a PostgreSQL expression index to find candidates, then the adapter filters and orders them. Index updates commit with the item, making GSI queries strongly consistent.
Transactions
TransactWriteItems executes in one PostgreSQL BEGIN…COMMIT transaction at SERIALIZABLE isolation. A debit in one table and a credit in another either both commit or both fail, as in DynamoDB.
Transactions enforce DynamoDB’s 100-action limit and one-operation-per-item rule. The adapter records ClientRequestToken in the same transaction as the writes. Within DynamoDB’s idempotency window, a retry with the same token returns the prior success without committing the writes again. The adapter acquires row locks in a consistent order to prevent opposite-direction transfers from deadlocking. Serialization or deadlock failures return retryable conflicts.
TransactWriteItems is not supported on stream-enabled tables. A request that touches any such table returns ValidationException before execution, because the transaction path does not create the required stream records.
TransactWriteItems runs in one native Postgres BEGIN…COMMIT at SERIALIZABLE, atomic and isolated across tables.
Limitations
PostgreSQL limitations- One PostgreSQL instance serves each table. Heavy contention on one key can cause serialization failures and row-lock conflicts. The adapter returns retryable errors, but sustained contention can exhaust the SDK retry budget and appear as throttling.
- Stream-enabled tables allow one writer at a time. An owner lease of about 90 seconds preserves stream record order. A second adapter instance attempting to write while that lease is active receives a retryable
ThrottlingException. Throughput depends on the writer, database and request workload. Tables without streams support concurrent writers. DescribeStreamlists at most 100 shards. A stream with more shards is not fully enumerated in one call.- Transactions on stream-enabled tables are unsupported. A
TransactWriteItemsrequest touching one returnsValidationExceptionbecause the transaction path does not create stream records. - DynamoDB backup and global-table APIs are unsupported. Use PostgreSQL backups, snapshots, point-in-time recovery (PITR), and replica/failover procedures. DynamoDB on-demand backup/restore, PITR, and global-table replication APIs are not implemented.
- Instances incur costs when idle. Size and pay for PostgreSQL capacity ahead of demand. Larger table counts require more instances and table-placement planning.
- Index lookups have a 10,000-item limit. A lookup that exceeds 10,000 candidate items for one index partition-key value returns an error.
- Plan for the table-count guardrail. The adapter checks 500 physical DynamoDB tables per namespace. Larger deployments need database capacity and table-placement planning.
- Expired items remain readable until deletion. A bounded, leader-elected reaper uses the TTL expression index to delete eligible rows asynchronously. Until physical deletion, GetItem, Query and Scan can return the expired item, and it continues to consume storage.
Other considerations
- Stream records commit with the write. The adapter stores each record in the table’s
_strmtable within the same transaction as the item write. A record exists if and only if its write committed. The single-writer lease keeps stream sequence order aligned with commit order so a cursor can resume without skipping records. - Use PostgreSQL recovery procedures. Backups, PITR, snapshots, and replica/failover procedures operate on the PostgreSQL database. The adapter does not implement DynamoDB backup, PITR, or global-table APIs.
- Connection pooling. The adapter uses pooled PostgreSQL connections. Deployments spread across many instances may need a separate pooler to keep total connections within each database’s limit.
- Migrate and test one table at a time. Separate PostgreSQL tables allow per-table export/import, dual-write, or backfill-and-switch procedures. Application code continues to use the DynamoDB API.
- Use PostgreSQL operational tools. Monitor SQL activity, maintain indexes, vacuum tables, and run backups with your existing PostgreSQL tools and procedures.
On Azure
Azure Cosmos DB (provisioned)
How it works
Tensor9 runs a DynamoDB adapter beside your application in the customer’s environment. It configuresAWS_ENDPOINT_URL_DYNAMODB to send the AWS SDK’s requests to the adapter over the local loopback network. Your SDK and application code stay unchanged. The adapter accepts DynamoDB requests and data types, returns DynamoDB responses and errors, and stores data in Azure Cosmos DB.
The adapter maps DynamoDB items and supported operations onto Cosmos documents. Native numeric precision, result pagination and transaction support differ from DynamoDB; the following sections describe those application-visible limits.
Your application uses the DynamoDB API through an adapter in the target environment.
Architecture
The adapter parses DynamoDB requests and expressions, executes Cosmos operations and returns DynamoDB responses. Durable item and registry state lives in Cosmos, and requests use the customer’s workload identity. Adapter instances can restart without recovering local data; stream-enabled tables still require one active writer. Tensor9 provisions one Cosmos account and oneddb database per stack, with a container for each declared table. The selected target sets provisioned or serverless throughput for the account. Items use table-prefixed partition keys; a reserved _tablemeta partition stores the schemas and creation times. Tables created at runtime share an existing container, as described below. LSIs share the source container; the provisioned target uses separate, asynchronously maintained GSI containers.
A stateless Rust adapter serves the DynamoDB API in front of Cosmos. One account and one “ddb” database hold a container per declared table, partitioned on /_pk. Runtime-created tables share a deployed container and its capacity.
The adapter first builds a storage-independent request plan, then converts it to a Cosmos-specific plan for execution. Each declared table has its own container; runtime-created tables share a deployed container and its capacity.
Schemas
The adapter preserves DynamoDB type tags inside theitem envelope. Accepted numbers are stored as native Cosmos JSON numbers; binary payloads use order-preserving hex. Keys and routing fields identify the logical table and partition.
Numeric precision differs: values must have at most 15 significant digits and fit the native numeric range. Values outside this supported representation fail validation before storage; the adapter does not preserve DynamoDB’s full 38-digit numeric domain as decimal strings.
Items remain limited to 400 KiB. Updates check the resulting item, including projected local-index entries where applicable. A larger Cosmos document limit does not disable this DynamoDB compatibility check.
Type tags distinguish numbers, strings, binary values and sets; native payloads make predicates queryable in Cosmos.
Where tables live
Each declared table has its own container, indexing policy and storage within the stack’s shared account and database. Containers share account administration and lifecycle. Monitor account limits as the number of tables grows. Choose provisioned or serverless throughput when selecting the target. Provisioned containers have an autoscale range of request units (RUs) derived from declared capacity; aPAY_PER_REQUEST source table gets a configurable default range. Serverless containers bill consumed requests and do not reserve the source table’s requested capacity. Throughput depends on request-unit use and partition distribution. Changing the selected target recreates the account and containers, so plan a data migration.
Within a container, a table-prefixed partition key such as orders|S:user#42 separates logical tables. Point reads and base queries use that _pk route; scans and registry reads filter on _tbl. Runtime CreateTable writes a registry document in the stack’s first deployed container. Its data identity has no permission to provision Cosmos containers. DescribeTable and ListTables read that registry.
- Key schema is required. A composite-key table’s key schema comes from a declared CreateTable, the registry doc, or is learned from the first key-bearing request. A Put that can’t resolve its key schema is rejected outright, never written under a guessed key.
- Declared tables are physically isolated; runtime-created tables are logically isolated. A declared table’s container (its throughput, its index, its storage) is its own. A table created at runtime shares a deployed container: its logical partitions are disjoint by table-prefixing, but physical partitions are shared. A hot logical partition remains bounded by the service capacity available to its physical partition.
A stack’s tables share one account and one “ddb” database, using the selected throughput mode. Each declared table has its own container; runtime-created tables share a deployed container and its capacity. At runtime, CreateTable / DeleteTable / UpdateTable change registry documents, not Cosmos resources.
Conditional writes
The operation and its options determine how the adapter writes an item. Ordinary SET updates use a versioned, partition-scoped stored procedure. Cosmos reads the current item, evaluates the condition, applies the update and checks the resulting 400 KiB item limit inside one atomic operation. This is read-modify-write inside the database, with no separate adapter read round trip. Native PATCH is narrower: the condition must prove existence, every action must be an eligible top-level removal, and TTL, streams and old-image requirements must be absent. A size-increasing SET cannot use this path because native PATCH cannot check the resulting DynamoDB item size. LSI updates, unsupported expressions and requests needing the old image on condition failure fall back to an adapter read and an etag-guarded write. Streamed writes use the guarded batch path to commit the item and outbox record together. A concurrent write conflict is retryable; it is not reported as a false condition failure. The Yahoo! Cloud Serving Benchmark (YCSB) workload F measures application-side read-modify-write: a separate GetItem before UpdateItem. Its full latency includes both API calls and is distinct from the update phase. That sequence is not a multi-item transaction. In the recorded 2026-09-09 provisioned capture with 16 workers, full read-modify-write p50 was 21.071 ms and update-phase p50 was 15.935 ms, reported as medians of three completed repetitions. These are different portions of the same workload, not two competing implementations.Secondary indexes
A local secondary index shares the source container and partition route, so its reads reflect committed writes immediately. Its projected entry size also contributes to DynamoDB’s item-size check. On the provisioned target, Azure asynchronously maintains a dedicated container for each declared global secondary index. Queries target that index container and push down its key predicate, ordering and cursor. GSI visibility is eventual;ConsistentRead=true is rejected, matching DynamoDB’s GSI contract.
Serverless tables cannot declare these managed GSIs. Index definitions must match the provisioned configuration; the adapter does not silently build a substitute index at runtime.
Transactions
The current Cosmos adapter rejects DynamoDB multi-item transactions. This includesTransactWriteItems, TransactGetItems and transactional PartiQL, even when all items share a partition key.
Cosmos partition-local stored procedures and batches still make individual writes and stream outbox commits atomic. That internal mechanism does not expose the DynamoDB transaction APIs.
Applications that require DynamoDB multi-item transactions need another listed target that supports those APIs.
Limitations
Compatibility limits- Numeric domain: at most 15 significant digits and representable native range, compared with DynamoDB’s 38-digit domain. Unsupported values fail validation.
- Item size: 400 KiB remains enforced. Ordinary SET updates use the stored procedure; LSI updates need the guarded fallback so projected entry size is checked too.
- Transactions: the current adapter rejects all DynamoDB multi-item transaction APIs, including single-partition requests.
- Read consistency: the compiled account uses Strong consistency regardless of the request’s ConsistentRead flag. Plan capacity for strongly consistent reads.
- Pagination: Query and Scan use native result windows. Limit and ScannedCount do not exactly reproduce DynamoDB’s pre-filter examined-item counter; residual predicates may be evaluated in the adapter.
- Indexes: managed GSIs are eventually consistent and require the provisioned target; LSIs share the source container. Declared index definitions must match the deployment.
- Streams: records co-commit with the item, but a streamed table permits one writing instance at a time to preserve ordering. Writes from another instance can be rejected until its writer lease is available.
- Hot partitions: capacity depends on key distribution and the account’s throughput mode. A hot item can contend even when aggregate capacity remains available.
- Table lifecycle: DeleteTable changes the logical generation. Other adapter instances can observe that change after the bounded metadata cache delay, approximately five seconds; physical cleanup is bounded.
Other considerations
- Migration: the Cosmos containers start empty. Export/import, backfill or a dual-write cutover must move existing DynamoDB data before switching traffic.
- Deployment: the compiler provisions one account with the chosen throughput mode, a shared database and containers for declared tables. Managed identities provide data access; account keys are unnecessary.
- Capacity: provisioned containers use dedicated autoscale RU bands. Serverless containers have no provisioned throughput and bill consumed requests. The 2026-09-09 adapter captures used separate Standard_D8s_v5 driver and adapter VMs in westus2, Strong consistency and gateway-mode connectivity. The provisioned container had a 40,000-RU/s autoscale maximum. YCSB used 100,000 verified records with ten 100-byte fields and 200,000 logical operations per repetition. Each mode has its own results; medians summarize three completed repetitions. There is no matching native DynamoDB baseline for this configuration, so these captures do not establish a performance advantage over DynamoDB.
- Runtime-created tables: these occupy separate logical namespaces inside an already-deployed container and share its capacity. Declared tables have separate containers.
- Operations: Microsoft operates Cosmos storage; Tensor9 operates the adapter. Monitor request units, throttling, write conflicts and latency alongside adapter and application host utilization.
Azure Cosmos DB (serverless)
Requests and database state
Your DynamoDB client sends requests to the Rust adapter in the target environment. The adapter parses DynamoDB expressions, performs Cosmos operations and returns DynamoDB responses. Cosmos stores items, table definitions and stream records. The adapter uses workload identity to access that data; restarting an adapter instance does not require restoring local item state.Choosing serverless capacity
Tensor9 provisions a serverless Cosmos account and one ddb database for the deployment. Charges follow consumed request units and stored data, without a dedicated autoscale range. The selected account mode applies to its containers; a source table’s provisioned capacity does not reserve Cosmos request units. Test the workload’s bursts, retries and partition distribution against the serverless limits.Declared and runtime-created tables
Each declared table gets a container. A table created through the runtime CreateTable API instead uses the first deployed container: the adapter records its schema and separates its items with a table-prefixed partition key. The data identity cannot provision a new Cosmos container. DescribeTable and ListTables read the durable registry; DeleteTable invalidates the table generation and performs bounded cleanup. Runtime-created tables therefore share container capacity.Items, reads and conditional writes
DynamoDB attribute type tags are retained, but numbers must fit the native Cosmos representation: at most 15 significant digits and a representable range. Unsupported numbers are rejected. The adapter enforces a 400 KiB item limit and uses strong reads regardless of ConsistentRead. Ordinary writes use a Cosmos stored procedure; eligible conditional removals use PATCH, and other request shapes use guarded read-modify-write. Query and Scan use Cosmos result windows, so Limit and ScannedCount differ from DynamoDB’s examined-item accounting.Indexes, transactions and streams
Local secondary indexes share the table’s container and reflect a write immediately. A global secondary index requires the provisioned target because the separate Azure-maintained index container needs autoscale throughput; declaring one on serverless stops the build. DynamoDB multi-item transaction APIs are rejected. Streams commit each change record with the item and require one writing instance per streamed table. All four view types and 24-hour retention are available; an older position returns TrimmedDataAccessException.Expiry, migration and operation
The adapter converts the configured absolute TTL epoch into Cosmos’s relative expiry value. Cosmos removes expired documents asynchronously. Deploy the destination, load existing items and validate the application’s queries and stream consumers before switching traffic. Changing between provisioned and serverless accounts requires a new destination and data migration. Microsoft operates Cosmos, while Tensor9 operates the adapter; configure account access, backups and monitoring for the target environment.On Google Cloud
Firestore
How it works
Tensor9 runs a DynamoDB adapter beside your application in the customer’s environment. It configuresAWS_ENDPOINT_URL_DYNAMODB to send the AWS SDK’s requests to the adapter over the local loopback network. Your SDK and application code stay unchanged. The adapter accepts DynamoDB requests and data types, returns DynamoDB responses and errors, and stores data in Google Cloud Firestore.
The adapter maps DynamoDB items, conditions, indexes and transactions onto Firestore documents. Numeric values must fit the native representation described below. Reads are strongly consistent, and write latency depends on whether the operation needs an initial read or encounters contention.
Your application uses the DynamoDB API through an adapter in the target environment.
Architecture
The adapter parses DynamoDB requests and expressions, executes Firestore operations and returns DynamoDB responses. Durable item and table state lives in Firestore. It authenticates with the customer’s workload identity. Instances can restart without recovering local data; stream-enabled tables still require one active writer. On the Firestore side there is no per-table container to provision. Every logical DynamoDB table lives in one Firestore collection,ddb, and each item is a document whose id encodes the table and the item’s key (orders|u#42), with a _tbl field that discriminates which logical table a document belongs to and a table-prefixed _pk field that routes a base Query to one partition’s documents. A reserved registry document holds the table registry (declared schemas and creation time), which is what lets a table your app creates at runtime be served with no Firestore provisioning (see the section on where tables live). Every DynamoDB item is stored so its exact types survive, and each declared secondary index is served by a Firestore composite index over the item’s existing tagged scalar fields. Because the adapter is stateless, this Firestore layout is the entire durable state of the system.
A stateless Rust adapter serves the DynamoDB API in front of Firestore; all durable state lives in one Firestore collection, “ddb”, where every logical table’s documents live together and are told apart by a _tbl field.
The adapter first builds a storage-independent request plan, then converts it to a Firestore-specific plan for execution.
Schemas
The envelope preserves DynamoDB’s type system without making values opaque to Firestore. Each attribute is a one-tag map: strings use{"S": stringValue}, numbers use {"N": integerValue|doubleValue}, binary uses {"B": bytesValue}, and sets, lists, maps, booleans, and null retain their own tags. That keeps a numeric value distinct from a numeric-looking string while allowing native filters and indexes to address paths such as item.total.N.
Native number storage has an explicit boundary. Signed 64-bit integral values remain exact Firestore integers; other numbers are accepted only inside a conservative 15-significant-digit double envelope. A DynamoDB number outside that envelope fails before storage instead of being rounded silently. The item map sits beside the routing fields id, _pk, _tbl, _okey, and _keyAttrs.
Each attribute keeps its DynamoDB type tag while scalar payloads use native Firestore values, so filters and secondary indexes can execute in storage.
Where tables live
Firestore is fully serverless: there is no account tier, no throughput mode, and no capacity band to size. Every DynamoDB table you declare is compiled into the same Firestore collection (ddb) , and each table’s documents are told apart by a _tbl discriminator and a table-prefixed document id and _pk route. Firestore shards documents automatically, and billing follows operations and stored data. Idle tables can still incur storage charges. A reserved registry document holds the declared schemas and creation times.
Runtime CreateTable writes the logical schema into the registry; DescribeTable and ListTables read it. DeleteTable invalidates the old table generation with one metadata write. Recreated tables use a new generation, such as orders#2. Old documents become invisible to the application and remain stored until bounded cleanup on a later same-name deletion.
- Key schema is required. A composite-key table’s key schema comes from a declared CreateTable, the registry document, or is learned from the first key-bearing request. A Put that can’t resolve its key schema is rejected outright, never written under a guessed key.
- Isolation is logical, not physical. Tables are kept apart by the
_tbldiscriminator and the table-prefixed id and_pk, all inside the project’s one Firestore database, which is shared across the project’s Firestore-backed apps. A pointGetItemand a baseQueryisolate by the table-prefixed route; only aScan(and the registry sweeps) filters on_tbl. Per-install physical isolation (a dedicated named database and a database-scoped identity) is not provided; the separation stays logical.
Every declared table shares one “ddb” collection, told apart by a _tbl discriminator; Firestore is fully serverless, so there is no throughput mode to pick. At runtime, CreateTable / DeleteTable / UpdateTable are pure data-plane ops on the registry, no Firestore admin call.
Conditional writes
A conditional write reads the document and itsupdateTime, evaluates the DynamoDB condition in the adapter, then writes only if that version still matches. Creation uses a does-not-exist precondition.
A false condition returns ConditionalCheckFailed. A concurrent write changing the document version returns a retryable conflict. The SDK can retry the latter without treating it as a failed application condition.
This path adds an item read before the guarded write. The retry is driven by your SDK’s backoff, not looped inside the layer. Even without contention, the read adds latency and a billed read operation. On a hot, heavily-contended document the conflict-and-retry loop can spend more time colliding than making progress, and a finite SDK retry budget can surface that contention to your app as a throttling failure.
Which writes avoid reading the item first?
Firestore’s native API supports masked field updates and atomic transforms, including increments. The DynamoDB adapter currently uses a narrower set of these capabilities:
- PutItem and DeleteItem: one direct document write when there is no condition,
ReturnValues=NONEand DynamoDB Streams is disabled. - UpdateItem with only top-level REMOVE actions: one masked document write when there is no condition,
ReturnValues=NONE, Streams is disabled and the update does not touch the configured TTL attribute. - SET and other updates, by default: read-modify-write. A blind SET cannot validate the resulting DynamoDB item’s 400-KiB limit, so the adapter reads the existing item before applying and validating the update. Arithmetic, nested updates, returned item attributes and TTL-attribute changes also take this path; Firestore’s native increment support is not currently used for DynamoDB numeric updates.
FIRESTORE_ALLOW_OVERSIZED_BLIND_UPDATES to "true" in the adapter configuration to enable blind top-level SET/REMOVE updates under the same no-condition, no-return-values, no-Streams and no-TTL-change requirements. Primary-key and secondary-index-key changes, and updates on tables with an LSI, retain the validated path. This option defaults to "false".
The option skips only the aggregate 400-KiB resulting-item check. Firestore still enforces its 1-MiB document limit, which includes the adapter’s type tags and metadata; that is not a 1-MiB DynamoDB payload allowance. PutItem, read-modify-write and transactions retain their checks. An item grown above 400 KiB may need a blind removal or replacement of a large attribute before validated writes succeed. No performance measurement is claimed for this opt-in.
The read-modify-write path computes the new item in the adapter and writes with a document-version precondition, preserving atomicity when another writer races. Performance for a direct write does not establish the latency of this path. Native primitives are described in the Firestore Write API.
False conditions and concurrent document changes return different errors.
Secondary indexes
Each declared global secondary index is served off the base document. The compiler creates ascending and descending Firestore composite indexes over_tbl, the tagged hash scalar, the optional tagged range scalar, and the document’s stable id. There are no synthetic GSI fields and no separate projected data copy. A re-key updates the index with the item write, a delete disappears with the item, and a sparse item is absent because a missing hash or range field has no matching index entry.
Consistency is therefore stronger than DynamoDB, whose GSIs are eventually consistent: here an index query reflects the write that just committed. Hash/range predicates, ordering, cursor, limit, and supported filters are pushed into Firestore; an unrepresentable application filter is evaluated over that bounded native window before the declared DynamoDB attribute set is returned. Native numeric fields compare numerically, and the id tie-break makes pagination exact when several items share one GSI range value. The index must still be declared at compile time; an undeclared index fails with a validation error rather than falling back to a silent table scan.
A declared GSI is a Firestore composite index over the item’s native tagged scalar fields; the full query window is selected and ordered in storage.
Transactions
TransactWriteItems becomes a real Firestore read-write transaction. The layer opens a transaction, reads each targeted document inside it, evaluates each item’s DynamoDB condition in the adapter (Firestore’s document preconditions aren’t expressive enough), stages the writes, and commits them atomically. A condition that fails rolls the whole transaction back with nothing written; a commit that loses a race is a transient conflict the SDK retries.
Transactions can span documents, logical tables and partition keys. The adapter enforces DynamoDB’s 100-action limit. A cancelled transaction returns a single conditional-failure signal rather than per-item CancellationReasons, so the application cannot identify the failed condition from that response.
TransactWriteItems maps to a real Firestore transaction across documents: atomic, durable, and isolated, with no single-partition restriction; both the debit and credit commit, or neither does.
Limitations
△ Where DynamoDB and Firestore diverge, read before you adopt- Concurrent writes to one document. Repeated updates to the same document can encounter version conflicts or throttling. SDK retries add latency and billed operations, and a finite retry budget can surface an error to the application. Size and test the workload for its actual key distribution.
- Most updates need read-modify-write by default. SET reads the item to enforce the 400-KiB resulting-item limit; conditions, arithmetic, nested updates and returned attributes also need a read. Eligible REMOVE-only updates use a direct masked write. The explicit oversized-blind-update option extends this to eligible SET/REMOVE while relaxing item-size fidelity. A document-version conflict on read-modify-write returns a retryable error; SDK retries repeat the work and add latency and billed operations.
- Isolation is logical, not physical. Every table lives in the project’s one shared Firestore database, kept apart by the
_tbldiscriminator and the table-prefixed id and_pk, not by a separate database or a per-table identity. There is no per-install physical isolation (a dedicated named database, a database-scoped identity); the separation stays logical. - Secondary indexes must be declared when your stack is compiled. That means the
global_secondary_indexblocks on youraws_dynamodb_table, read when Tensor9 compiles your stack for release. It is not your application’s build, and not something it can do at runtime: adding an index means editing your Terraform and releasing again.CreateTablemay still name indexes, but they must match the ones already compiled in, andUpdateTablecannot introduce a new one. A GSI is served by Firestore composite indexes over native tagged item fields, which is synchronous and strongly consistent (stronger read visibility than DynamoDB’s eventually-consistent GSIs). The runtime cannot learn an index definition from traffic: querying one that was never declared returns a validation error rather than a silent table scan.ConsistentRead=trueis rejected on a global secondary index, matching DynamoDB’s GSI contract;ConsistentRead=falseis accepted. Local secondary indexes accept strongly consistent reads. The flag restriction does not change the synchronous physical index updates. - Reads are always strongly consistent. A single-document read reflects the latest committed write, regardless of
ConsistentRead. Estimate Firestore document and index-entry read charges for the actual queries. - Some filters run in the compute layer. Equality, bounded
IN, and compatible type predicates compile to native tagged item fields and run in Firestore. InFilterExpression,<>,attribute_not_exists,contains,begins_with,NOT, and predicates whose Firestore ordering would conflict with DynamoDB key order are evaluated by the service adapter over the bounded native key/range/cursor window. A stringbegins_withon a GSI sort key is still pushed down as a native access range. - A streamed table has one writing instance at a time. DynamoDB Streams are served from an ordered change-log document co-committed with each write in one transaction, which requires a single writer per streamed table: a second concurrent instance’s write is rejected as a retryable throttle until the writer lease passes. Run streamed-table writers at one replica; tables without a stream take concurrent writers safely, and reads are unaffected.
- Dropped-table storage needs cleanup.
DeleteTableinvalidates the current table generation with one metadata write. Old documents become invisible immediately but remain stored until bounded cleanup on a later deletion of the same table name. Large tables can therefore continue consuming storage after deletion. - Transaction cancellation is coarse. A cancelled
TransactWriteItemscurrently returns a single conditional-failure signal rather than DynamoDB’s per-itemCancellationReasons, so an app can’t yet tell which item’s condition failed.
Other considerations
- Data migration. The Firestore store starts empty. Move existing DynamoDB data through an export/import, backfill or dual-write procedure, and validate it before switching traffic.
- Operations and ownership. Google operates Firestore; Tensor9 operates the adapter. The adapter uses workload identity and short-lived credentials. The customer manages the Google Cloud project, cluster maintenance and monitoring.
- Capacity planning. Firestore bills operations and storage without provisioned throughput. Query and Scan select bounded native windows; unsupported application filters run over those windows in the adapter. Estimate charges from examined documents and index entries, and test contention on frequently updated documents.
- Read consistency. The request flag does not select an eventual-read path. Include strongly consistent reads when sizing the workload and estimating charges.
- Change streams. DynamoDB Streams are served from an ordered change-log document co-committed with each write, retained for a fixed window, and read back through the Streams API (all four view types). Ordering requires a single writer per streamed table; tables without a stream are unaffected.
Cloud Spanner
How it works
Your application keeps its AWS SDK, endpoint configuration, and DynamoDB item formats. The Tensor9 adapter accepts DynamoDB requests and stores data in Spanner. The adapter compiles aQuery’s key condition, filter, ordering, and limit into one GoogleSQL statement for Spanner to execute. Selective key ranges reduce work. Filters can still examine rows that are not returned, so compute consumption depends on more than the result size.
The application keeps calling the DynamoDB JSON API. The adapter translates it into GoogleSQL against Spanner.
Architecture
Spanner executes the SQL query, including its key condition, filter, ordering, and limit.
Rows and keys
Each DynamoDB table becomes a Spanner table. An item is one row, keyed first by its partition key and then by its sort key. This layout lets Spanner read a key range in order and applyScanIndexForward and pagination through the index.
Attribute values retain their DynamoDB types: decimal numbers preserve precision, binary remains binary, and strings and sets retain the distinctions the API requires.
The adapter encodes numeric values as sortable decimal text and normalizes sets. Spanner can evaluate supported comparisons in GoogleSQL over that representation without converting numbers to floating point.
The table also stores local index and expiry information. A local secondary index is interleaved with its table, so its entries are stored with the row they describe. Where a table declares a TTL attribute, the expiry is a generated column derived from that attribute, which a Spanner row-deletion policy uses, so expiry is physical deletion on Spanner’s schedule, not a hide-on-read filter the adapter applies.
Partition and sort keys form the Spanner primary key, which supports ordered range reads.
Transactions and consistency
TransactWriteItems uses a Spanner read-write transaction across tables and partition keys. Spanner’s external consistency also orders transactions in real time. The adapter enforces the 100-action limit, one operation per item and the ClientRequestToken idempotency window.
The adapter reads and locks items whose conditions or changes require their current values, evaluates the conditions, then commits the transaction. A failed condition and a concurrency conflict return distinct errors so the client can decide whether to retry. A requested failed-item image is returned with the condition error.
An unconditional Put can skip reading the item because it supplies the complete replacement. Conditions, returned prior values, updates computed from existing attributes and delete-size accounting require the existing item to be read.
DynamoDB’s aggregate limits are enforced as its own, not Spanner’s: each resulting item is validated against the 400 KiB item limit, and the transaction as a whole against DynamoDB’s 4 MiB aggregate item-data cap. A request that would exceed either fails the way it fails on AWS.
The adapter’s normal reads are strongly consistent, including requests with ConsistentRead=false. That flag does not select a cheaper or faster stale-read path. Strong reads on a global secondary index remain rejected for DynamoDB compatibility.
Transactions can span tables and partition keys. External consistency preserves transaction order in real time.
Secondary indexes
A global secondary index becomes a Spanner secondary index, and a local secondary index an index interleaved with its table. AQuery against either is an index seek, not a table scan.
Spanner commits secondary-index updates with the row. A subsequent strong index read includes that committed update. DynamoDB GSIs propagate asynchronously, so applications that tolerate index lag do not need to add that wait on this target.
Because the index is a real Spanner index rather than a projected copy, the query engine does the selection. The key condition, ordering, cursor and limit all lower into the index scan, so a selective index query reads close to what it returns rather than filtering a wider read afterwards. A sparse item, one missing the index’s key attribute, simply has no index entry, matching DynamoDB’s own sparse-index behaviour.
Two rules are inherited from the origin rather than from Spanner. You still cannot request a strongly-consistent read of a global secondary index: ConsistentRead=true against one is rejected, exactly as DynamoDB rejects it. And a query that asks for attributes the index does not project is rejected rather than silently fetching them from the base row, so an index with too few attributes for the query returns an error without fetching extra rows. The wire behaviour is the same as the origin’s, so code that handles those errors on AWS handles them here unchanged.
Spanner commits row and index updates together. A subsequent strong index read includes the update.
Limitations
△ Where DynamoDB and Spanner diverge, read before you adopt- Provisioned compute bills through quiet periods. Both services charge for stored data; Spanner also charges for provisioned compute. Steady utilization can amortize it, but savings depend on workload, capacity, region and replication topology.
- A hot item still contends. The adapter hashes partition routes to spread independent keys. Repeated updates to one item still compete; a uniform-key benchmark does not establish hot-item performance.
- A projected index cannot serve a full-item read.
Select=ALL_ATTRIBUTESagainst a global secondary index that does not project every attribute is rejected rather than quietly fetching the missing columns from the base table. The error names the index, so the fix is either to query the attributes the index already has, or to declare it so it includes them all. - Scan competes for provisioned compute. Paging limits response size, but a broad scan still reads the table and competes with point operations. Prefer a selective
Querywhen possible. - DynamoDB Streams are not served. The write executor rejects stream-enabled writes. Use another backend if the application requires an atomic DynamoDB change log.
- Some writes use read-modify-write. Conditions, responses that need the existing item, nested updates, arithmetic, changes to secondary-index keys and updates to tables with an LSI take this path. The adapter reads the item, evaluates the condition and computes the change, then commits it in the same Spanner transaction. A transaction conflict can repeat that work. Eligible top-level SET/REMOVE updates avoid the item read; this can include
UPDATED_NEWwhen the response is known from assigned values. - Measured latency depends on the request type. The 2026-08-31 workload measured simple unconditional updates. It does not measure the extra read or conflict retries of read-modify-write. The run used 1,000 processing units in us-west1, 100,000 records and a 50/50 read/update workload. With 16 worker threads, steady median throughput was 2,403.0 operations/s through Spanner versus 5,929.5 on native DynamoDB in us-west-2, using three 200,000-operation repetitions after warm-up. Spanner served strong reads; DynamoDB served eventual reads. The standalone adapter capture excluded Cloud Adapter deployment authorization and durable control-plane logging. These are complete-path results with different regions and consistency, not isolated adapter overhead or measurements of transactions and hot-item contention.
Other considerations
- Data migration. The Spanner database is provisioned empty. Existing DynamoDB items are not moved in place. Load them through the adapter’s DynamoDB API, validate the data and representative queries before switching application traffic. For an online migration, coordinate backfill and ongoing writes so changes made during the copy reach Spanner before cutover.
- Capacity planning. Size Spanner compute in processing units. Start from the read and write rates the DynamoDB table was provisioned for rather than from its storage size, and expect to tune once under real load. Spanner’s throughput per unit depends heavily on how well the primary key distributes.
- Operations and ownership. Google operates Spanner: replication, backups, and failover are theirs. Tensor9 operates the adapter. Spanner stores the data; the adapter runs beside the application.
- Authentication. The adapter authenticates to Spanner with the workload’s own identity through GKE Workload Identity. There is no key file and no secret to rotate.
Cloud Bigtable
How it works
Tensor9 runs a DynamoDB adapter beside your application in the customer’s environment. It configuresAWS_ENDPOINT_URL_DYNAMODB to send the AWS SDK’s requests to the adapter over the local loopback network. Your SDK and application code stay unchanged. The adapter accepts DynamoDB requests and data types, returns DynamoDB responses and errors, and stores data in Google Cloud Bigtable. It connects to Bigtable over pooled gRPC using the workload identity; no key file is required.
Bigtable provides atomic writes for one row, not across rows , and the adapter maps each DynamoDB item to exactly one row. The adapter uses row mutations and version guards for item writes. This mapping rejects multi-item transactions, secondary indexes, DynamoDB Streams and per-item TTL; the limitations below describe the missing behavior.
Your application uses the DynamoDB API through an adapter in the target environment.
Architecture
The adapter translates DynamoDB keys and operations into Bigtable row keys, row ranges and mutations. Ordered key ranges implement base-table queries. DynamoDB attribute filters run in the adapter over the selected rows. A conditional write reads the item, evaluates the DynamoDB condition and usesCheckAndMutateRow to commit only if the row version still matches. Another writer changing the row triggers a retry of the read and condition check.
The adapter first builds a storage-independent request plan, then converts it to a Bigtable-specific plan for execution.
One row per item
Every logical DynamoDB table lives in one provisioned Bigtable table, and each item is one row there. A metadata row records each logical schema and its generation, so the logical tables stay separated inside the shared physical one rather than colliding. The row key is what makes reads efficient. It is laid out as the logical table, then the partition route, then the collated sort key, then an item digest. A generation identifier separates each table incarnation, so a table dropped and recreated cannot read its predecessor’s rows. Because the sort key is collated into the key in DynamoDB’s own order, one DynamoDB partition becomes one contiguous Bigtable range, and aQuery over a key range is a range read in the right order rather than a filter over unrelated rows.
Item data lives in a raw column family. A second family is an INT64 SUM aggregate, which exists so an integral counter can be updated by Bigtable itself in a single round trip instead of being read, added to and written back. See the next section.
The row key is built so a DynamoDB partition is one contiguous Bigtable range, in the origin’s sort order.
Writes and atomicity
An unconditionalPutItem or DeleteItem, and a top-level SET/REMOVE UpdateItem, use a single MutateRow, with no read of the old item and one round trip. A single integral numeric ADD, or a SET computed from the attribute’s own current value, uses Bigtable’s INT64 SUM aggregate cell, so Bigtable performs the addition itself in one RPC rather than the adapter reading, adding and writing back.
Conditions, returned item values, nested changes and arithmetic beyond the supported counter case require a read. The adapter computes the change and commits it with CheckAndMutateRow against a version field. Conflicting writes repeat the read and condition check, up to eight attempts.
All of this is atomic for one item and linearizable because the configured app profile routes to a single cluster. Multi-cluster routing would break the row-transaction contract, so the adapter verifies the routing and the column-family contracts through the Bigtable Admin API at startup, before it serves any traffic, rather than discovering a misconfiguration under load.
A top-level SET/REMOVE that skips the item read cannot check the size of the item it produces, so that path relaxes DynamoDB’s aggregate 400 KiB limit. An application that depends on that limit being enforced exactly should use a backend that reads before writing.
Simple mutations and supported counters can avoid a read; other writes read the item and use a version guard.
Reads and filters
AQuery is a range read. Because the sort key is encoded in DynamoDB order in the row key, the key condition, the direction and the page boundary are all served by the row range itself, and results come back in DynamoDB’s order without the adapter re-sorting them.
For a FilterExpression, filters are evaluated in the adapter, not in storage. Bigtable’s own row filters work on families, qualifiers and versions rather than on DynamoDB’s typed attribute predicates, so the adapter reads the range and applies your filter to the items it read. As a result, a filtered read can read more rows than it returns, and a highly selective filter over a wide range costs what the range costs, not what the result costs. Prefer a selective key condition over a broad range plus a filter.
Scan pages through the table the same way. Paging bounds the response, but a broad scan still reads the rows it passes over and competes with point operations for the instance’s provisioned capacity.
Reads are strongly consistent through the single-cluster app profile. ConsistentRead=false does not select a cheaper or staler path. A request that would be eventually consistent on DynamoDB is simply served strongly here.
A filtered read examines every row in the selected key range. The adapter returns only rows that match the filter.
Limitations
The following features require operations across multiple rows or per-item deletion rules that this Bigtable layout cannot provide. The adapter rejects these requests.- Multi-item transactions.
TransactWriteItems,TransactGetItemsand transactional PartiQL are rejected: Bigtable cannot atomically commit or snapshot several item rows. An application that needs cross-item atomicity wants Spanner or a Postgres target. - Secondary indexes. A GSI or LSI query is not served. There is no maintained index to seek, so the adapter rejects these requests without scanning the table. Native Bigtable materialized views are not exposed as DynamoDB indexes either.
- DynamoDB Streams. Not served. Bigtable change streams are not a DynamoDB-compatible atomic change log. A stream record cannot be committed in the same atomic unit as the write it describes.
- Per-item TTL. Bigtable does expire data, but only through a column-family garbage-collection policy: a uniform max age or version count for the whole family. DynamoDB’s TTL is per item, driven by an epoch attribute the application sets on each row, and a family-wide rule cannot express that. Configuring TTL fails rather than silently applying a different expiry rule.
- The blind-write size check. A top-level SET/REMOVE that skips the read also skips the aggregate 400 KiB validation, as described above.
- Filters are adapter-side. A filtered read can read more rows than it returns; see the previous section.
- A hot item still contends. Row keys spread independent partitions, but repeated updates to one item serialize on that row. A uniform-key benchmark does not predict hot-item behaviour.
Cloud SQL for PostgreSQL
How it works
Tensor9 runs a DynamoDB adapter beside your application in the customer’s environment. It configuresAWS_ENDPOINT_URL_DYNAMODB to send the AWS SDK’s requests to the adapter over the local loopback network. Your SDK and application code stay unchanged. The adapter accepts DynamoDB requests and data types, returns DynamoDB responses and errors, and stores data in PostgreSQL.
DynamoDB supports numbers with up to 38 significant digits, typed sets, conditional writes, secondary indexes, and atomic transactions. The adapter implements these using PostgreSQL storage and transactions. PostgreSQL supports multi-table transactions and synchronously updated indexes, but has different concurrency, capacity, and identifier limits. Unsupported requests return errors; the limitations below describe the differences.
For base-table Query and Scan requests, the adapter compiles supported filters into parameterized SQL WHERE predicates over the JSONB item. Number comparisons cast stored decimal text to PostgreSQL numeric. An order-preserving key column supplies sort bounds, cursor position, and direction. The query uses a server-side cursor to fetch bounded batches until the requested Limit or 1 MiB of item data. Expressions that cannot be represented in SQL are evaluated in the adapter over the rows selected by the SQL predicate. Secondary-index queries use the separate path described below.
For conditional writes, the adapter opens a transaction, locks the row with SELECT ... FOR UPDATE, evaluates the ConditionExpression, and writes within that transaction. This requires an extra round trip, but prevents a concurrent writer from changing the item between the check and write. A failed condition returns ConditionalCheckFailed and can return the item that failed it. Some unconditional writes skip the read: a top-level SET/REMOVE patch or integral counter add uses one statement when it has no condition, requests no returned item image, and affects no secondary index or stream.
Your application uses the DynamoDB API through an adapter in the target environment.
Architecture
The adapter is a stateless Rust service. It parses DynamoDB expressions, translates requests into PostgreSQL operations, and returns DynamoDB responses. It connects to PostgreSQL through a connection pool using the customer’s credentials. Durable state stays in PostgreSQL, so adapter instances can restart or scale out without coordinating local state. Stream-enabled tables have the separate single-writer restriction below. Each DynamoDB table has a PostgreSQL table namedddb_<name> in one database. The ddb_tables registry records its generated physical name, key schema, billing mode, time-to-live (TTL) settings, global secondary indexes (GSIs), and stream settings. A write or query for a table absent from the registry returns ResourceNotFoundException; writes do not create tables implicitly. At runtime, CreateTable creates a PostgreSQL expression index for each declared GSI. Each stream-enabled table also has a _strm table that stores change records.
A stateless Rust adapter serves the DynamoDB API in front of Postgres; all durable state lives in one Postgres database, where each DynamoDB table is its own physical relation.
The adapter first builds a storage-independent request plan, then converts it to a Postgres-specific plan for execution.
Schemas
A DynamoDB item occupies one PostgreSQL row with columnspk TEXT, sk TEXT, okey TEXT and item JSONB. The PRIMARY KEY (pk, sk) index serves GetItem. A separate index over pk and bytewise-collated okey serves ordered base-table Query requests.
The item JSONB column preserves DynamoDB’s typed attribute representation, including {"N":"123.45"}, {"B":"<b64>"}, and typed sets. Numbers remain decimal strings, so a 38-digit amount or a Snowflake ID is not rounded through a floating-point conversion. Type tags preserve the distinction between numbers and numeric strings. Conditional writes use row locks, not a separate version column. Enabling TTL builds an expression index over the configured epoch attribute inside the JSONB item. A bounded, leader-elected reaper deletes eligible rows through that index. Expired items remain readable until physical deletion; reads do not filter on TTL.
Each attribute keeps its DynamoDB type tag inside item JSONB , so {“N”:“123.45”} keeps its exact decimal string.
Where tables live
Each DynamoDB table has its own PostgreSQL table, indexes and optional_strm change-record table. CreateTable creates those database objects and their registry entry; DeleteTable drops them. Storage, indexes and vacuum settings can be tuned per table.
The adapter checks a 500-table guardrail per namespace when creating a physical DynamoDB table. Concurrent creates of different tables can exceed that guardrail; it is not a hard PostgreSQL quota. Plan database capacity and table placement for larger deployments. Provisioned instances continue to incur compute costs while idle.
Each declared table is its own physical relation. CreateTable and DeleteTable create and drop PostgreSQL relations. The adapter applies a 500-table guardrail per namespace.
Conditional writes
To evaluate a conditional write, the adapter locks the item’s(pk, sk) row with SELECT … FOR UPDATE, checks the ConditionExpression against that row, then writes and commits. The lock prevents another writer from changing the item between the check and write.
A false condition returns the non-retryable ConditionalCheckFailed error. A PostgreSQL serialization failure or lock timeout (40001/lock-not-available) instead returns a retryable throughput error, allowing the SDK to back off and retry. Concurrency failures are not reported as failed conditions.
For attribute_not_exists(pk), the PostgreSQL primary-key constraint prevents two concurrent requests from creating the same item. Only one insert can succeed for a given (pk, sk).
Failed conditions and PostgreSQL concurrency conflicts return different error types.
Secondary indexes
On each write, the adapter adds two index fields to the item’s JSONB. The partition-key field,_idx_<name>_h, normalizes equivalent values such as 1 and 1.0. The sort-key field, _idx_<name>_o, preserves sort order and uses the base key to break ties. A PostgreSQL expression index over these fields locates matching partition keys. The adapter then evaluates sort-key conditions, ordering, pagination, and any FilterExpression over the retrieved items.
The index fields and item commit in the same transaction, so GSI queries are strongly consistent. DynamoDB’s own GSIs update asynchronously and are eventually consistent. Each index lookup is limited to 10,000 candidate items for one index partition-key value. Exceeding this limit returns an error; choose index keys with this limit in mind.
A GSI uses a PostgreSQL expression index to find candidates, then the adapter filters and orders them. Index updates commit with the item, making GSI queries strongly consistent.
Transactions
TransactWriteItems executes in one PostgreSQL BEGIN…COMMIT transaction at SERIALIZABLE isolation. A debit in one table and a credit in another either both commit or both fail, as in DynamoDB.
Transactions enforce DynamoDB’s 100-action limit and one-operation-per-item rule. The adapter records ClientRequestToken in the same transaction as the writes. Within DynamoDB’s idempotency window, a retry with the same token returns the prior success without committing the writes again. The adapter acquires row locks in a consistent order to prevent opposite-direction transfers from deadlocking. Serialization or deadlock failures return retryable conflicts.
TransactWriteItems is not supported on stream-enabled tables. A request that touches any such table returns ValidationException before execution, because the transaction path does not create the required stream records.
TransactWriteItems runs in one native Postgres BEGIN…COMMIT at SERIALIZABLE, atomic and isolated across tables.
Limitations
PostgreSQL limitations- One PostgreSQL instance serves each table. Heavy contention on one key can cause serialization failures and row-lock conflicts. The adapter returns retryable errors, but sustained contention can exhaust the SDK retry budget and appear as throttling.
- Stream-enabled tables allow one writer at a time. An owner lease of about 90 seconds preserves stream record order. A second adapter instance attempting to write while that lease is active receives a retryable
ThrottlingException. Throughput depends on the writer, database and request workload. Tables without streams support concurrent writers. DescribeStreamlists at most 100 shards. A stream with more shards is not fully enumerated in one call.- Transactions on stream-enabled tables are unsupported. A
TransactWriteItemsrequest touching one returnsValidationExceptionbecause the transaction path does not create stream records. - DynamoDB backup and global-table APIs are unsupported. Use PostgreSQL backups, snapshots, point-in-time recovery (PITR), and replica/failover procedures. DynamoDB on-demand backup/restore, PITR, and global-table replication APIs are not implemented.
- Instances incur costs when idle. Size and pay for PostgreSQL capacity ahead of demand. Larger table counts require more instances and table-placement planning.
- Index lookups have a 10,000-item limit. A lookup that exceeds 10,000 candidate items for one index partition-key value returns an error.
- Plan for the table-count guardrail. The adapter checks 500 physical DynamoDB tables per namespace. Larger deployments need database capacity and table-placement planning.
- Expired items remain readable until deletion. A bounded, leader-elected reaper uses the TTL expression index to delete eligible rows asynchronously. Until physical deletion, GetItem, Query and Scan can return the expired item, and it continues to consume storage.
Other considerations
- Stream records commit with the write. The adapter stores each record in the table’s
_strmtable within the same transaction as the item write. A record exists if and only if its write committed. The single-writer lease keeps stream sequence order aligned with commit order so a cursor can resume without skipping records. - Use PostgreSQL recovery procedures. Backups, PITR, snapshots, and replica/failover procedures operate on the PostgreSQL database. The adapter does not implement DynamoDB backup, PITR, or global-table APIs.
- Connection pooling. The adapter uses pooled PostgreSQL connections. Deployments spread across many instances may need a separate pooler to keep total connections within each database’s limit.
- Migrate and test one table at a time. Separate PostgreSQL tables allow per-table export/import, dual-write, or backfill-and-switch procedures. Application code continues to use the DynamoDB API.
- Use PostgreSQL operational tools. Monitor SQL activity, maintain indexes, vacuum tables, and run backups with your existing PostgreSQL tools and procedures.
On OCI
OCI NoSQL Database
Infrastructure mapping
Tensor9 converts the declared aws_dynamodb_table to an oci_nosql_table in the customer’s OCI compartment. This is the infrastructure-only adaptation: it provisions storage but does not provide an AWS DynamoDB endpoint. Application reads, writes, queries and runtime table administration use OCI NoSQL APIs. The table and control pages describe this same target choice.Keys and item data
The DynamoDB partition key becomes the OCI SHARD key. An optional sort key becomes the second primary-key column. String, number and binary key types become corresponding OCI column types; other item attributes occupy a value JSON column. Adapt queries and serialization to that layout rather than sending DynamoDB attribute documents directly.Capacity and storage
PAY_PER_REQUEST selects OCI ON_DEMAND; provisioned DynamoDB capacity selects OCI PROVISIONED settings. OCI read and write units differ from DynamoDB units, so validate them against the workload. OCI also requires an explicit storage cap. Increase that cap before data reaches it; the source DynamoDB table had no equivalent fixed cap.Indexes, expiry and integrations
The current infrastructure mapping does not create declared GSIs or LSIs. Configure native OCI indexes and update the application’s access patterns. A source TTL declaration produces a no-expiry default; its per-item epoch attribute is not translated into automatic expiry. DynamoDB Streams, AWS PITR configuration, source KMS key references and replica settings are not reproduced by this table resource. Configure the corresponding target data-protection and event requirements separately.Migration and operation
The new table starts empty. Convert application access, load the data, and test key lookups, queries, expiry and recovery before switching traffic. Oracle operates the NoSQL service; the customer manages compartment access, capacity, storage limits and the chosen recovery procedures. Use a different listed adaptation when the application must keep runtime DynamoDB API calls.On Scaleway
Scaleway Managed Database for PostgreSQL
Table administration
Table administration and item operations use separate adapter surfaces, but they select the same target backend.On Akamai, DigitalOcean, Private Kubernetes, and Scaleway
PostgreSQL
Table administration on Tensor9-managed PostgreSQL
The application’s DynamoDB client sends table-management requests to the Tensor9 adapter in the target environment. The control endpoint and the table endpoint use the same target database. Tensor9 deploys PostgreSQL with the Cloud Adapter deployment and serves the DynamoDB control API through the adapter. CreateTable creates the item table, secondary indexes and registry metadata inside that database. Applications continue to use DynamoDB table names and key definitions.Capacity settings
Capacity comes from the database resources allocated in the target environment. DynamoDB billing-mode changes remain table metadata and do not resize the deployment. The adapter applies a 500-table guardrail per namespace, so deployments with larger table fleets need a different layout or target.Deletion and durable state
Creation writes the table schema and registry together in a PostgreSQL transaction. Deletion drops the item table and its stream change log and removes table metadata and stream-owner records in the same transaction. ListTables reports the surviving registry entries.Configuration and retry constraints
Time-to-live configuration builds the required index before enabling expiry. Table creation, deletion and index work consume the same database resources used by item requests. Size the deployment for both schema changes and steady application traffic.Operating the target
Tensor9 operates this database within the Cloud Adapter deployment, including disconnected deployments, rather than relying on a cloud-managed PostgreSQL service. Storage durability, backup and recovery depend on the Cloud Adapter deployment configuration and available customer infrastructure. The DynamoDB table contract remains the same PostgreSQL-backed contract described for the managed target.On Azure
Azure Cosmos DB (provisioned)
Table administration on Azure Cosmos DB (provisioned throughput)
The application’s DynamoDB client sends table-management requests to the Tensor9 adapter in the target environment. The control endpoint and the table endpoint use the same target database. The deployed table uses a Cosmos DB container with an autoscale range of request units. Runtime CreateTable records logical table metadata in the configured container; it does not create another Cosmos account or a new independently sized container for every request.Capacity settings
The provisioned target uses an autoscale range of request units, or RUs, sized for the declared table. UpdateTable retains DynamoDB billing settings in the table registry. Change the Cosmos throughput configuration to change the actual capacity available to the container.Deletion and durable state
The registry stores table names, key definitions and lifecycle state. DeleteTable marks the logical table deleted and advances its generation; a recreated name uses the new generation so older items are no longer reachable through it. Physical cleanup is separate from this logical deletion.Configuration and retry constraints
Runtime CreateTable index definitions must match the deployed secondary-index configuration. The stream specification must also match the deployed configuration. Provisioned throughput can support Azure-managed global secondary indexes; plan those indexes with the deployment rather than treating runtime table creation as an unrestricted container-design API.Operating the target
Microsoft operates database durability, backups and availability. Tensor9 translates DynamoDB control requests and maintains the logical table registry. Native Cosmos account and container management remain separate from this endpoint; numeric precision, transactions and stream ownership are covered with the item APIs above.Azure Cosmos DB (serverless)
Table administration on Azure Cosmos DB (serverless)
The application’s DynamoDB client sends table-management requests to the Tensor9 adapter in the target environment. The control endpoint and the table endpoint use the same target database. The adapter serves table administration over a configured serverless Cosmos DB container. CreateTable registers a logical table and its key schema in that container. ListTables and DescribeTable read the stored registry rather than discovering a separate Azure resource for each logical name.Capacity settings
Cosmos DB charges for consumed request units and storage in this target. DynamoDB billing settings are retained as metadata; UpdateTable cannot switch the Cosmos account from serverless to provisioned throughput. Choose that operating mode when selecting the target.Deletion and durable state
DeleteTable hides a table by changing its registry state and advancing its generation. Recreating the same name starts a new logical generation, with old items excluded from reads and listings. Cleanup of old documents can continue after the logical deletion.Configuration and retry constraints
Azure-managed global secondary indexes require the provisioned target and are not offered on this serverless target. Runtime index definitions and stream settings must match the deployed configuration. A table that needs managed global secondary indexes should select provisioned Cosmos DB before deployment.Operating the target
Microsoft operates the Cosmos database while Tensor9 operates the adapter. Configure native backup and account access separately. Serverless consumption billing does not remove the documented Cosmos limits on numeric precision, multi-item transactions or stream ownership.On Google Cloud
Firestore
Table administration on Google Cloud Firestore
The application’s DynamoDB client sends table-management requests to the Tensor9 adapter in the target environment. The control endpoint and the table endpoint use the same target database. CreateTable stores the key schema and table settings in a registry document. The table shares a Firestore collection with other logical tables. ListTables reads the registry, so it can return newly created tables before they contain any items.Capacity settings
Firestore bills native document operations and storage. UpdateTable retains DynamoDB billing settings in the registry; those settings do not create DynamoDB-style reserved read or write capacity in Firestore.Deletion and durable state
DeleteTable changes the registry to mark the table deleted and advances its generation number. Item reads, index entries and stream records use that generation, so recreating the same table name starts with an empty logical table even while old documents await cleanup.Configuration and retry constraints
Physical cleanup is bounded and may leave unreachable documents behind. Those documents still consume storage until removed. Account for cleanup and Firestore document charges in environments that repeatedly create and delete large tables.Operating the target
The adapter stores table settings durably in Firestore and uses workload identity to access the database. Configure native backups and database access separately. Stream-enabled tables retain the single-writer requirement described for the item APIs above.Cloud Spanner
Table administration on Google Cloud Spanner
The application’s DynamoDB client sends table-management requests to the Tensor9 adapter in the target environment. The control endpoint and the table endpoint use the same target database. CreateTable records the requested key and index definitions, then creates the corresponding Spanner tables and indexes. DeleteTable removes those objects. ListTables and DescribeTable use the durable table catalog.Capacity settings
Spanner capacity belongs to the instance. DynamoDB billing-mode and throughput settings are retained as table metadata; changing them does not allocate a separate pool of Spanner processing units for that table.Deletion and durable state
The catalog records creation and deletion before the associated schema work finishes. A retried create can resume matching unfinished work; a request with a different schema cannot reuse that unfinished creation. This makes retry behavior relevant when a client times out during a schema change.Configuration and retry constraints
Spanner schema changes can take longer than item requests. Allow time for table creation and retain normal SDK retry handling. A deleted table must finish its recorded teardown before its name can be created again.Operating the target
Configure the Spanner instance, database access and backup policy for the target environment. This control endpoint manages DynamoDB tables within that database; it does not turn per-table capacity settings into Spanner instance administration. DynamoDB Streams remain outside this mapping.Cloud Bigtable
Table lifecycle
The DynamoDB adapter manages logical tables inside an existing Bigtable table. CreateTable records the table name and key schema; it does not create a Bigtable instance or allocate a separate cluster. DescribeTable and ListTables return the adapter’s table catalog. Provision the Bigtable instance, physical table, column families and single-cluster app profile before using these APIs.Capacity and supported configuration
Bigtable cluster capacity is shared by the logical tables. Changing DynamoDB billing-mode metadata does not add Bigtable nodes or enforce provisioned read and write units. The adapter rejects secondary indexes, DynamoDB Streams and per-item TTL; selecting those options cannot make the underlying row store provide those DynamoDB behaviors.Deletion and storage cleanup
DeleteTable removes a logical table’s visibility through the DynamoDB API. A table generation separates a recreated name from its predecessor’s rows. Logical deletion does not delete the Bigtable cluster or its shared physical table; the provisioned store remains. Plan storage cleanup and account for retained storage costs after deleting a logical table.Cloud SQL for PostgreSQL
Table administration on Google Cloud SQL for PostgreSQL
The application’s DynamoDB client sends table-management requests to the Tensor9 adapter in the target environment. The control endpoint and the table endpoint use the same target database. CreateTable creates a PostgreSQL table, its declared secondary indexes and a registry entry. A stream-enabled table also receives a change-log table. The DynamoDB endpoint serves both table administration and item requests against this same database.Capacity settings
Cloud SQL instance size, storage and availability settings determine capacity. UpdateTable records DynamoDB billing settings without resizing the Cloud SQL instance. The adapter applies a 500-table guardrail per namespace; this is an adapter limit rather than a PostgreSQL service quota.Deletion and durable state
Table creation writes the schema and registry in a database transaction. DeleteTable drops the item table and its change log and removes the registry and stream-owner records in the same transaction. Recreating the name therefore does not expose the deleted table’s records.Configuration and retry constraints
Enabling time to live builds the needed PostgreSQL index before advertising the setting as enabled. The API waits for that index work while normal item reads and writes remain available. Plan schema changes with enough database capacity and request timeout allowance.Operating the target
Google operates the Cloud SQL database; Tensor9 operates the DynamoDB adapter and uses Cloud SQL IAM database authentication. Configure database backups and availability through Cloud SQL. The table page describes transaction behavior and stream-related restrictions.On OCI
OCI NoSQL Database
Infrastructure mapping
Tensor9 converts the declared aws_dynamodb_table to an oci_nosql_table in the customer’s OCI compartment. This is the infrastructure-only adaptation: it provisions storage but does not provide an AWS DynamoDB endpoint. Application reads, writes, queries and runtime table administration use OCI NoSQL APIs. The table and control pages describe this same target choice.Keys and item data
The DynamoDB partition key becomes the OCI SHARD key. An optional sort key becomes the second primary-key column. String, number and binary key types become corresponding OCI column types; other item attributes occupy a value JSON column. Adapt queries and serialization to that layout rather than sending DynamoDB attribute documents directly.Capacity and storage
PAY_PER_REQUEST selects OCI ON_DEMAND; provisioned DynamoDB capacity selects OCI PROVISIONED settings. OCI read and write units differ from DynamoDB units, so validate them against the workload. OCI also requires an explicit storage cap. Increase that cap before data reaches it; the source DynamoDB table had no equivalent fixed cap.Indexes, expiry and integrations
The current infrastructure mapping does not create declared GSIs or LSIs. Configure native OCI indexes and update the application’s access patterns. A source TTL declaration produces a no-expiry default; its per-item epoch attribute is not translated into automatic expiry. DynamoDB Streams, AWS PITR configuration, source KMS key references and replica settings are not reproduced by this table resource. Configure the corresponding target data-protection and event requirements separately.Migration and operation
The new table starts empty. Convert application access, load the data, and test key lookups, queries, expiry and recovery before switching traffic. Oracle operates the NoSQL service; the customer manages compartment access, capacity, storage limits and the chosen recovery procedures. Use a different listed adaptation when the application must keep runtime DynamoDB API calls.On Scaleway
Scaleway Managed Database for PostgreSQL
Service level agreements
Listed terms cover requests sent through this service adapter. They do not cover direct connections to the target service or replace the cloud provider’s own SLA. Each origin-to-target pair has its own terms or an explicit pending status. See the SLA tables, measurement rules, and scaling conditions.DynamoDB to Azure Cosmos DB (provisioned)
What this adapter does
Forazure::1.0.0::cosmosdb::provisioned, Cosmos stores typed items in documents. Updates may use conditional PATCH, a partition-scoped stored procedure, or an ETag-guarded read/modify/write. Query windows and partition boundaries matter. Provisioned and serverless accounts retain their distinct throughput and index restrictions. The 1 ms point-operation objective is deliberately narrow. A conditional write, scanned page, transaction or control-plane request uses its own row. Stored procedures or SQL that implement the application operation are target execution; adapter catalog, coordination and retry work must not be mislabeled as application-database wait.
How the latency targets were chosen
Table and configuration API responses: 20 ms monthly p99.CreateTable, DeleteTable, DescribeTable, ListTables, UpdateTable. Logical-table catalogs and lifecycle state must be persisted and validated. Their storage latency is adapter work even when the catalog uses the same database as application items.
Your signed agreement sets the terms for your deployment. A target does not add an operation or option that the compatibility tables mark unavailable.
What counts toward latency
For a request-response row, measure from the agreed ingress boundary to dispatch of the complete response. A row that explicitly names a first response chunk ends at that chunk; its number does not cover the rest of the stream. A long-poll row names the intentional wait and when adapter delay starts. Include parsing, authorization, admission, translation, serialization, adapter-owned storage and coordination, retries and response handling. Subtract only separately measured target-workload waits and external network segments allowed by the measurement rules. The adapter’s own response handling and dispatch remain covered. A database used for adapter metadata is still adapter work, even if a cloud provider hosts it. For concurrent calls, exclude the union of permitted wait intervals, not the sum of overlapping spans. Calculate each request’s adapter duration first, then the monthly p99. Do not subtract one service’s p99 from another’s. Known adapter timeouts are over-budget samples; failed or incomplete requests cannot disappear to improve the percentile. Missing measurements do not become zero latency. An SDK call span alone does not prove how much of its duration can be excluded.Availability and failures
The 99.9% request target measures correct adapter handling, not the percentage of application calls that return success. Correctly forwarding a target quota or permission error is different from producing that error because the adapter sent the wrong request. Adapter-caused failures count even when the target is healthy. With 1,000,000 eligible calls in a month, a 99.9% target permits at most 1,000 adapter-attributable failures. Endpoint probes have their own denominator. Correctness defects remain actionable even when the monthly availability percentage is met.Scaling and target-service capacity
Watch adapter CPU and allocation rate alongside target read/write capacity, partition hot spots and connection/session limits. Scale adapter replicas on outstanding work, not QPS alone: a 100-item scan and a GetItem differ substantially. Tensor9 is responsible for autoscaling within the agreed per-operation concurrency, item-size, page and burst limits. The customer selects and sizes the target, including Cosmos RU/s, Spanner capacity or SQL connections; scaling the adapter cannot remove a hot partition or a database quota. Tell Tensor9 the expected steady rate, bursts, concurrency, payload sizes and operation mix. Tensor9 sizes and scales the adapter for the agreed load; you choose and monitor the target service’s capacity with Tensor9’s help. A latency budget is not a requests-per-second rating. Larger requests and higher rates need explicit terms, not silent inheritance of a small-request SLA.Data and behavior guarantees
Conditional writes must not silently lose their condition, and a transaction must not report atomic success after a partial commit. Exact number representation, consistency, secondary-index behavior and stream ordering remain those documented for this target. A request outside that support is rejected or handled as explicitly documented, not made correct by meeting a latency percentile. The underlying database’s durability commitment is not a Tensor9 storage SLA.Example and diagnosis
Inorders, GetItem for a 3 KiB item uses the point-read row. Query that examines 90 items but returns only two still uses the page row. An UpdateItem with a version condition uses the conditional-write row. In Explain, compare adapter expression/planning/serialization work with the measured target operation; a rise in Cosmos throttling or Spanner execution time is different from a rise in adapter queueing or catalog lookups.
Use tensor9 explain and the documented explain headers to understand the selected adapter and its behavior. Correlate available request diagnostics with the target provider’s latency, throttling and capacity metrics. An explain report helps diagnose a request; it is not by itself a qualified SLA timing measurement. Share the operation, request shape, timestamps and request identifiers with support, with credentials and customer payloads removed.
DynamoDB to Azure Cosmos DB (serverless)
What this adapter does
Forazure::1.0.0::cosmosdb::serverless, Cosmos stores typed items in documents. Updates may use conditional PATCH, a partition-scoped stored procedure, or an ETag-guarded read/modify/write. Query windows and partition boundaries matter. Provisioned and serverless accounts retain their distinct throughput and index restrictions. The 1 ms point-operation objective is deliberately narrow. A conditional write, scanned page, transaction or control-plane request uses its own row. Stored procedures or SQL that implement the application operation are target execution; adapter catalog, coordination and retry work must not be mislabeled as application-database wait.
How the latency targets were chosen
Table and configuration API responses: 20 ms monthly p99.CreateTable, DeleteTable, DescribeTable, ListTables, UpdateTable. Logical-table catalogs and lifecycle state must be persisted and validated. Their storage latency is adapter work even when the catalog uses the same database as application items.
Your signed agreement sets the terms for your deployment. A target does not add an operation or option that the compatibility tables mark unavailable.
What counts toward latency
For a request-response row, measure from the agreed ingress boundary to dispatch of the complete response. A row that explicitly names a first response chunk ends at that chunk; its number does not cover the rest of the stream. A long-poll row names the intentional wait and when adapter delay starts. Include parsing, authorization, admission, translation, serialization, adapter-owned storage and coordination, retries and response handling. Subtract only separately measured target-workload waits and external network segments allowed by the measurement rules. The adapter’s own response handling and dispatch remain covered. A database used for adapter metadata is still adapter work, even if a cloud provider hosts it. For concurrent calls, exclude the union of permitted wait intervals, not the sum of overlapping spans. Calculate each request’s adapter duration first, then the monthly p99. Do not subtract one service’s p99 from another’s. Known adapter timeouts are over-budget samples; failed or incomplete requests cannot disappear to improve the percentile. Missing measurements do not become zero latency. An SDK call span alone does not prove how much of its duration can be excluded.Availability and failures
The 99.9% request target measures correct adapter handling, not the percentage of application calls that return success. Correctly forwarding a target quota or permission error is different from producing that error because the adapter sent the wrong request. Adapter-caused failures count even when the target is healthy. With 1,000,000 eligible calls in a month, a 99.9% target permits at most 1,000 adapter-attributable failures. Endpoint probes have their own denominator. Correctness defects remain actionable even when the monthly availability percentage is met.Scaling and target-service capacity
Watch adapter CPU and allocation rate alongside target read/write capacity, partition hot spots and connection/session limits. Scale adapter replicas on outstanding work, not QPS alone: a 100-item scan and a GetItem differ substantially. Tensor9 is responsible for autoscaling within the agreed per-operation concurrency, item-size, page and burst limits. The customer selects and sizes the target, including Cosmos RU/s, Spanner capacity or SQL connections; scaling the adapter cannot remove a hot partition or a database quota. Tell Tensor9 the expected steady rate, bursts, concurrency, payload sizes and operation mix. Tensor9 sizes and scales the adapter for the agreed load; you choose and monitor the target service’s capacity with Tensor9’s help. A latency budget is not a requests-per-second rating. Larger requests and higher rates need explicit terms, not silent inheritance of a small-request SLA.Data and behavior guarantees
Conditional writes must not silently lose their condition, and a transaction must not report atomic success after a partial commit. Exact number representation, consistency, secondary-index behavior and stream ordering remain those documented for this target. A request outside that support is rejected or handled as explicitly documented, not made correct by meeting a latency percentile. The underlying database’s durability commitment is not a Tensor9 storage SLA.Example and diagnosis
Inorders, GetItem for a 3 KiB item uses the point-read row. Query that examines 90 items but returns only two still uses the page row. An UpdateItem with a version condition uses the conditional-write row. In Explain, compare adapter expression/planning/serialization work with the measured target operation; a rise in Cosmos throttling or Spanner execution time is different from a rise in adapter queueing or catalog lookups.
Use tensor9 explain and the documented explain headers to understand the selected adapter and its behavior. Correlate available request diagnostics with the target provider’s latency, throttling and capacity metrics. An explain report helps diagnose a request; it is not by itself a qualified SLA timing measurement. Share the operation, request shape, timestamps and request identifiers with support, with credentials and customer payloads removed.
DynamoDB to Cloud Bigtable
What this adapter does
Forgoogle::1.0.0::bigtable, Items use row-atomic Bigtable storage. Multi-item transactions and unsupported secondary-index/stream semantics do not become covered merely because point reads are covered. The 1 ms point-operation objective is deliberately narrow. A conditional write, scanned page, transaction or control-plane request uses its own row. Stored procedures or SQL that implement the application operation are target execution; adapter catalog, coordination and retry work must not be mislabeled as application-database wait.
How the latency targets were chosen
Table and configuration API responses: 20 ms monthly p99.CreateTable, DeleteTable, DescribeTable, ListTables, UpdateTable. Logical-table catalogs and lifecycle state must be persisted and validated. Their storage latency is adapter work even when the catalog uses the same database as application items.
Your signed agreement sets the terms for your deployment. A target does not add an operation or option that the compatibility tables mark unavailable.
What counts toward latency
For a request-response row, measure from the agreed ingress boundary to dispatch of the complete response. A row that explicitly names a first response chunk ends at that chunk; its number does not cover the rest of the stream. A long-poll row names the intentional wait and when adapter delay starts. Include parsing, authorization, admission, translation, serialization, adapter-owned storage and coordination, retries and response handling. Subtract only separately measured target-workload waits and external network segments allowed by the measurement rules. The adapter’s own response handling and dispatch remain covered. A database used for adapter metadata is still adapter work, even if a cloud provider hosts it. For concurrent calls, exclude the union of permitted wait intervals, not the sum of overlapping spans. Calculate each request’s adapter duration first, then the monthly p99. Do not subtract one service’s p99 from another’s. Known adapter timeouts are over-budget samples; failed or incomplete requests cannot disappear to improve the percentile. Missing measurements do not become zero latency. An SDK call span alone does not prove how much of its duration can be excluded.Availability and failures
The 99.9% request target measures correct adapter handling, not the percentage of application calls that return success. Correctly forwarding a target quota or permission error is different from producing that error because the adapter sent the wrong request. Adapter-caused failures count even when the target is healthy. With 1,000,000 eligible calls in a month, a 99.9% target permits at most 1,000 adapter-attributable failures. Endpoint probes have their own denominator. Correctness defects remain actionable even when the monthly availability percentage is met.Scaling and target-service capacity
Watch adapter CPU and allocation rate alongside target read/write capacity, partition hot spots and connection/session limits. Scale adapter replicas on outstanding work, not QPS alone: a 100-item scan and a GetItem differ substantially. Tensor9 is responsible for autoscaling within the agreed per-operation concurrency, item-size, page and burst limits. The customer selects and sizes the target, including Cosmos RU/s, Spanner capacity or SQL connections; scaling the adapter cannot remove a hot partition or a database quota. Tell Tensor9 the expected steady rate, bursts, concurrency, payload sizes and operation mix. Tensor9 sizes and scales the adapter for the agreed load; you choose and monitor the target service’s capacity with Tensor9’s help. A latency budget is not a requests-per-second rating. Larger requests and higher rates need explicit terms, not silent inheritance of a small-request SLA.Data and behavior guarantees
Conditional writes must not silently lose their condition, and a transaction must not report atomic success after a partial commit. Exact number representation, consistency, secondary-index behavior and stream ordering remain those documented for this target. A request outside that support is rejected or handled as explicitly documented, not made correct by meeting a latency percentile. The underlying database’s durability commitment is not a Tensor9 storage SLA.Example and diagnosis
Inorders, GetItem for a 3 KiB item uses the point-read row. Query that examines 90 items but returns only two still uses the page row. An UpdateItem with a version condition uses the conditional-write row. In Explain, compare adapter expression/planning/serialization work with the measured target operation; a rise in Cosmos throttling or Spanner execution time is different from a rise in adapter queueing or catalog lookups.
Use tensor9 explain and the documented explain headers to understand the selected adapter and its behavior. Correlate available request diagnostics with the target provider’s latency, throttling and capacity metrics. An explain report helps diagnose a request; it is not by itself a qualified SLA timing measurement. Share the operation, request shape, timestamps and request identifiers with support, with credentials and customer payloads removed.
DynamoDB to Cloud SQL for PostgreSQL
What this adapter does
Forgoogle::1.0.0::cloudsql::postgresql, The SQL-backed adapter maps items, expressions and indexes onto relational rows and transactions. Row locks, index maintenance, stream outboxes and transaction conflict handling can add work beyond a single statement. The 1 ms point-operation objective is deliberately narrow. A conditional write, scanned page, transaction or control-plane request uses its own row. Stored procedures or SQL that implement the application operation are target execution; adapter catalog, coordination and retry work must not be mislabeled as application-database wait.
How the latency targets were chosen
Table and configuration API responses: 20 ms monthly p99.CreateTable, DeleteTable, DescribeTable, ListTables, UpdateTable. Logical-table catalogs and lifecycle state must be persisted and validated. Their storage latency is adapter work even when the catalog uses the same database as application items.
Your signed agreement sets the terms for your deployment. A target does not add an operation or option that the compatibility tables mark unavailable.
What counts toward latency
For a request-response row, measure from the agreed ingress boundary to dispatch of the complete response. A row that explicitly names a first response chunk ends at that chunk; its number does not cover the rest of the stream. A long-poll row names the intentional wait and when adapter delay starts. Include parsing, authorization, admission, translation, serialization, adapter-owned storage and coordination, retries and response handling. Subtract only separately measured target-workload waits and external network segments allowed by the measurement rules. The adapter’s own response handling and dispatch remain covered. A database used for adapter metadata is still adapter work, even if a cloud provider hosts it. For concurrent calls, exclude the union of permitted wait intervals, not the sum of overlapping spans. Calculate each request’s adapter duration first, then the monthly p99. Do not subtract one service’s p99 from another’s. Known adapter timeouts are over-budget samples; failed or incomplete requests cannot disappear to improve the percentile. Missing measurements do not become zero latency. An SDK call span alone does not prove how much of its duration can be excluded.Availability and failures
The 99.9% request target measures correct adapter handling, not the percentage of application calls that return success. Correctly forwarding a target quota or permission error is different from producing that error because the adapter sent the wrong request. Adapter-caused failures count even when the target is healthy. With 1,000,000 eligible calls in a month, a 99.9% target permits at most 1,000 adapter-attributable failures. Endpoint probes have their own denominator. Correctness defects remain actionable even when the monthly availability percentage is met.Scaling and target-service capacity
Watch adapter CPU and allocation rate alongside target read/write capacity, partition hot spots and connection/session limits. Scale adapter replicas on outstanding work, not QPS alone: a 100-item scan and a GetItem differ substantially. Tensor9 is responsible for autoscaling within the agreed per-operation concurrency, item-size, page and burst limits. The customer selects and sizes the target, including Cosmos RU/s, Spanner capacity or SQL connections; scaling the adapter cannot remove a hot partition or a database quota. Tell Tensor9 the expected steady rate, bursts, concurrency, payload sizes and operation mix. Tensor9 sizes and scales the adapter for the agreed load; you choose and monitor the target service’s capacity with Tensor9’s help. A latency budget is not a requests-per-second rating. Larger requests and higher rates need explicit terms, not silent inheritance of a small-request SLA.Data and behavior guarantees
Conditional writes must not silently lose their condition, and a transaction must not report atomic success after a partial commit. Exact number representation, consistency, secondary-index behavior and stream ordering remain those documented for this target. A request outside that support is rejected or handled as explicitly documented, not made correct by meeting a latency percentile. The underlying database’s durability commitment is not a Tensor9 storage SLA.Example and diagnosis
Inorders, GetItem for a 3 KiB item uses the point-read row. Query that examines 90 items but returns only two still uses the page row. An UpdateItem with a version condition uses the conditional-write row. In Explain, compare adapter expression/planning/serialization work with the measured target operation; a rise in Cosmos throttling or Spanner execution time is different from a rise in adapter queueing or catalog lookups.
Use tensor9 explain and the documented explain headers to understand the selected adapter and its behavior. Correlate available request diagnostics with the target provider’s latency, throttling and capacity metrics. An explain report helps diagnose a request; it is not by itself a qualified SLA timing measurement. Share the operation, request shape, timestamps and request identifiers with support, with credentials and customer payloads removed.
DynamoDB to Firestore
What this adapter does
Forgoogle::1.0.0::firestore, The adapter translates typed items to Firestore documents and uses the documented transactional behavior. Residual filtering, pagination and index choices determine how many documents the adapter must inspect for one DynamoDB response. The 1 ms point-operation objective is deliberately narrow. A conditional write, scanned page, transaction or control-plane request uses its own row. Stored procedures or SQL that implement the application operation are target execution; adapter catalog, coordination and retry work must not be mislabeled as application-database wait.
How the latency targets were chosen
Table and configuration API responses: 20 ms monthly p99.CreateTable, DeleteTable, DescribeTable, ListTables, UpdateTable. Logical-table catalogs and lifecycle state must be persisted and validated. Their storage latency is adapter work even when the catalog uses the same database as application items.
Your signed agreement sets the terms for your deployment. A target does not add an operation or option that the compatibility tables mark unavailable.
What counts toward latency
For a request-response row, measure from the agreed ingress boundary to dispatch of the complete response. A row that explicitly names a first response chunk ends at that chunk; its number does not cover the rest of the stream. A long-poll row names the intentional wait and when adapter delay starts. Include parsing, authorization, admission, translation, serialization, adapter-owned storage and coordination, retries and response handling. Subtract only separately measured target-workload waits and external network segments allowed by the measurement rules. The adapter’s own response handling and dispatch remain covered. A database used for adapter metadata is still adapter work, even if a cloud provider hosts it. For concurrent calls, exclude the union of permitted wait intervals, not the sum of overlapping spans. Calculate each request’s adapter duration first, then the monthly p99. Do not subtract one service’s p99 from another’s. Known adapter timeouts are over-budget samples; failed or incomplete requests cannot disappear to improve the percentile. Missing measurements do not become zero latency. An SDK call span alone does not prove how much of its duration can be excluded.Availability and failures
The 99.9% request target measures correct adapter handling, not the percentage of application calls that return success. Correctly forwarding a target quota or permission error is different from producing that error because the adapter sent the wrong request. Adapter-caused failures count even when the target is healthy. With 1,000,000 eligible calls in a month, a 99.9% target permits at most 1,000 adapter-attributable failures. Endpoint probes have their own denominator. Correctness defects remain actionable even when the monthly availability percentage is met.Scaling and target-service capacity
Watch adapter CPU and allocation rate alongside target read/write capacity, partition hot spots and connection/session limits. Scale adapter replicas on outstanding work, not QPS alone: a 100-item scan and a GetItem differ substantially. Tensor9 is responsible for autoscaling within the agreed per-operation concurrency, item-size, page and burst limits. The customer selects and sizes the target, including Cosmos RU/s, Spanner capacity or SQL connections; scaling the adapter cannot remove a hot partition or a database quota. Tell Tensor9 the expected steady rate, bursts, concurrency, payload sizes and operation mix. Tensor9 sizes and scales the adapter for the agreed load; you choose and monitor the target service’s capacity with Tensor9’s help. A latency budget is not a requests-per-second rating. Larger requests and higher rates need explicit terms, not silent inheritance of a small-request SLA.Data and behavior guarantees
Conditional writes must not silently lose their condition, and a transaction must not report atomic success after a partial commit. Exact number representation, consistency, secondary-index behavior and stream ordering remain those documented for this target. A request outside that support is rejected or handled as explicitly documented, not made correct by meeting a latency percentile. The underlying database’s durability commitment is not a Tensor9 storage SLA.Example and diagnosis
Inorders, GetItem for a 3 KiB item uses the point-read row. Query that examines 90 items but returns only two still uses the page row. An UpdateItem with a version condition uses the conditional-write row. In Explain, compare adapter expression/planning/serialization work with the measured target operation; a rise in Cosmos throttling or Spanner execution time is different from a rise in adapter queueing or catalog lookups.
Use tensor9 explain and the documented explain headers to understand the selected adapter and its behavior. Correlate available request diagnostics with the target provider’s latency, throttling and capacity metrics. An explain report helps diagnose a request; it is not by itself a qualified SLA timing measurement. Share the operation, request shape, timestamps and request identifiers with support, with credentials and customer payloads removed.
DynamoDB to Cloud Spanner
What this adapter does
Forgoogle::1.0.0::spanner, The adapter lowers DynamoDB reads and writes into GoogleSQL and Spanner physical plans. Simple point calls differ from expression evaluation, secondary-index maintenance and transaction planning. Table DDL is asynchronous and has a separate control-plane path. The 1 ms point-operation objective is deliberately narrow. A conditional write, scanned page, transaction or control-plane request uses its own row. Stored procedures or SQL that implement the application operation are target execution; adapter catalog, coordination and retry work must not be mislabeled as application-database wait.
How the latency targets were chosen
Table and configuration API responses: 20 ms monthly p99.CreateTable, DeleteTable, DescribeTable, ListTables, UpdateTable. Logical-table catalogs and lifecycle state must be persisted and validated. Their storage latency is adapter work even when the catalog uses the same database as application items.
Your signed agreement sets the terms for your deployment. A target does not add an operation or option that the compatibility tables mark unavailable.
What counts toward latency
For a request-response row, measure from the agreed ingress boundary to dispatch of the complete response. A row that explicitly names a first response chunk ends at that chunk; its number does not cover the rest of the stream. A long-poll row names the intentional wait and when adapter delay starts. Include parsing, authorization, admission, translation, serialization, adapter-owned storage and coordination, retries and response handling. Subtract only separately measured target-workload waits and external network segments allowed by the measurement rules. The adapter’s own response handling and dispatch remain covered. A database used for adapter metadata is still adapter work, even if a cloud provider hosts it. For concurrent calls, exclude the union of permitted wait intervals, not the sum of overlapping spans. Calculate each request’s adapter duration first, then the monthly p99. Do not subtract one service’s p99 from another’s. Known adapter timeouts are over-budget samples; failed or incomplete requests cannot disappear to improve the percentile. Missing measurements do not become zero latency. An SDK call span alone does not prove how much of its duration can be excluded.Availability and failures
The 99.9% request target measures correct adapter handling, not the percentage of application calls that return success. Correctly forwarding a target quota or permission error is different from producing that error because the adapter sent the wrong request. Adapter-caused failures count even when the target is healthy. With 1,000,000 eligible calls in a month, a 99.9% target permits at most 1,000 adapter-attributable failures. Endpoint probes have their own denominator. Correctness defects remain actionable even when the monthly availability percentage is met.Scaling and target-service capacity
Watch adapter CPU and allocation rate alongside target read/write capacity, partition hot spots and connection/session limits. Scale adapter replicas on outstanding work, not QPS alone: a 100-item scan and a GetItem differ substantially. Tensor9 is responsible for autoscaling within the agreed per-operation concurrency, item-size, page and burst limits. The customer selects and sizes the target, including Cosmos RU/s, Spanner capacity or SQL connections; scaling the adapter cannot remove a hot partition or a database quota. Tell Tensor9 the expected steady rate, bursts, concurrency, payload sizes and operation mix. Tensor9 sizes and scales the adapter for the agreed load; you choose and monitor the target service’s capacity with Tensor9’s help. A latency budget is not a requests-per-second rating. Larger requests and higher rates need explicit terms, not silent inheritance of a small-request SLA.Data and behavior guarantees
Conditional writes must not silently lose their condition, and a transaction must not report atomic success after a partial commit. Exact number representation, consistency, secondary-index behavior and stream ordering remain those documented for this target. A request outside that support is rejected or handled as explicitly documented, not made correct by meeting a latency percentile. The underlying database’s durability commitment is not a Tensor9 storage SLA.Example and diagnosis
Inorders, GetItem for a 3 KiB item uses the point-read row. Query that examines 90 items but returns only two still uses the page row. An UpdateItem with a version condition uses the conditional-write row. In Explain, compare adapter expression/planning/serialization work with the measured target operation; a rise in Cosmos throttling or Spanner execution time is different from a rise in adapter queueing or catalog lookups.
Use tensor9 explain and the documented explain headers to understand the selected adapter and its behavior. Correlate available request diagnostics with the target provider’s latency, throttling and capacity metrics. An explain report helps diagnose a request; it is not by itself a qualified SLA timing measurement. Share the operation, request shape, timestamps and request identifiers with support, with credentials and customer payloads removed.
DynamoDB to OCI NoSQL Database
SLA status: Not applicable The mapping provisions OCI NoSQL tables without exposing a DynamoDB management endpoint. There is no DynamoDB request-serving fabric on this path.DynamoDB to PostgreSQL
What this adapter does
Forpostgres::1.0.0::database, The SQL-backed adapter maps items, expressions and indexes onto relational rows and transactions. Row locks, index maintenance, stream outboxes and transaction conflict handling can add work beyond a single statement. The 1 ms point-operation objective is deliberately narrow. A conditional write, scanned page, transaction or control-plane request uses its own row. Stored procedures or SQL that implement the application operation are target execution; adapter catalog, coordination and retry work must not be mislabeled as application-database wait.
How the latency targets were chosen
Table and configuration API responses: 20 ms monthly p99.CreateTable, DeleteTable, DescribeTable, ListTables, UpdateTable. Logical-table catalogs and lifecycle state must be persisted and validated. Their storage latency is adapter work even when the catalog uses the same database as application items.
Your signed agreement sets the terms for your deployment. A target does not add an operation or option that the compatibility tables mark unavailable.
What counts toward latency
For a request-response row, measure from the agreed ingress boundary to dispatch of the complete response. A row that explicitly names a first response chunk ends at that chunk; its number does not cover the rest of the stream. A long-poll row names the intentional wait and when adapter delay starts. Include parsing, authorization, admission, translation, serialization, adapter-owned storage and coordination, retries and response handling. Subtract only separately measured target-workload waits and external network segments allowed by the measurement rules. The adapter’s own response handling and dispatch remain covered. A database used for adapter metadata is still adapter work, even if a cloud provider hosts it. For concurrent calls, exclude the union of permitted wait intervals, not the sum of overlapping spans. Calculate each request’s adapter duration first, then the monthly p99. Do not subtract one service’s p99 from another’s. Known adapter timeouts are over-budget samples; failed or incomplete requests cannot disappear to improve the percentile. Missing measurements do not become zero latency. An SDK call span alone does not prove how much of its duration can be excluded.Availability and failures
The 99.9% request target measures correct adapter handling, not the percentage of application calls that return success. Correctly forwarding a target quota or permission error is different from producing that error because the adapter sent the wrong request. Adapter-caused failures count even when the target is healthy. With 1,000,000 eligible calls in a month, a 99.9% target permits at most 1,000 adapter-attributable failures. Endpoint probes have their own denominator. Correctness defects remain actionable even when the monthly availability percentage is met.Scaling and target-service capacity
Watch adapter CPU and allocation rate alongside target read/write capacity, partition hot spots and connection/session limits. Scale adapter replicas on outstanding work, not QPS alone: a 100-item scan and a GetItem differ substantially. Tensor9 is responsible for autoscaling within the agreed per-operation concurrency, item-size, page and burst limits. The customer selects and sizes the target, including Cosmos RU/s, Spanner capacity or SQL connections; scaling the adapter cannot remove a hot partition or a database quota. Tell Tensor9 the expected steady rate, bursts, concurrency, payload sizes and operation mix. Tensor9 sizes and scales the adapter for the agreed load; you choose and monitor the target service’s capacity with Tensor9’s help. A latency budget is not a requests-per-second rating. Larger requests and higher rates need explicit terms, not silent inheritance of a small-request SLA.Data and behavior guarantees
Conditional writes must not silently lose their condition, and a transaction must not report atomic success after a partial commit. Exact number representation, consistency, secondary-index behavior and stream ordering remain those documented for this target. A request outside that support is rejected or handled as explicitly documented, not made correct by meeting a latency percentile. The underlying database’s durability commitment is not a Tensor9 storage SLA.Example and diagnosis
Inorders, GetItem for a 3 KiB item uses the point-read row. Query that examines 90 items but returns only two still uses the page row. An UpdateItem with a version condition uses the conditional-write row. In Explain, compare adapter expression/planning/serialization work with the measured target operation; a rise in Cosmos throttling or Spanner execution time is different from a rise in adapter queueing or catalog lookups.
Use tensor9 explain and the documented explain headers to understand the selected adapter and its behavior. Correlate available request diagnostics with the target provider’s latency, throttling and capacity metrics. An explain report helps diagnose a request; it is not by itself a qualified SLA timing measurement. Share the operation, request shape, timestamps and request identifiers with support, with credentials and customer payloads removed.
DynamoDB to Scaleway Managed Database for PostgreSQL
What this adapter does
Forscaleway::1.0.0::rdb::postgresql, The SQL-backed adapter maps items, expressions and indexes onto relational rows and transactions. Row locks, index maintenance, stream outboxes and transaction conflict handling can add work beyond a single statement. The 1 ms point-operation objective is deliberately narrow. A conditional write, scanned page, transaction or control-plane request uses its own row. Stored procedures or SQL that implement the application operation are target execution; adapter catalog, coordination and retry work must not be mislabeled as application-database wait.
How the latency targets were chosen
Table and configuration API responses: 20 ms monthly p99.CreateTable, DeleteTable, DescribeTable, ListTables. Logical-table catalogs and lifecycle state must be persisted and validated. Their storage latency is adapter work even when the catalog uses the same database as application items.
Your signed agreement sets the terms for your deployment. A target does not add an operation or option that the compatibility tables mark unavailable.
What counts toward latency
For a request-response row, measure from the agreed ingress boundary to dispatch of the complete response. A row that explicitly names a first response chunk ends at that chunk; its number does not cover the rest of the stream. A long-poll row names the intentional wait and when adapter delay starts. Include parsing, authorization, admission, translation, serialization, adapter-owned storage and coordination, retries and response handling. Subtract only separately measured target-workload waits and external network segments allowed by the measurement rules. The adapter’s own response handling and dispatch remain covered. A database used for adapter metadata is still adapter work, even if a cloud provider hosts it. For concurrent calls, exclude the union of permitted wait intervals, not the sum of overlapping spans. Calculate each request’s adapter duration first, then the monthly p99. Do not subtract one service’s p99 from another’s. Known adapter timeouts are over-budget samples; failed or incomplete requests cannot disappear to improve the percentile. Missing measurements do not become zero latency. An SDK call span alone does not prove how much of its duration can be excluded.Availability and failures
The 99.9% request target measures correct adapter handling, not the percentage of application calls that return success. Correctly forwarding a target quota or permission error is different from producing that error because the adapter sent the wrong request. Adapter-caused failures count even when the target is healthy. With 1,000,000 eligible calls in a month, a 99.9% target permits at most 1,000 adapter-attributable failures. Endpoint probes have their own denominator. Correctness defects remain actionable even when the monthly availability percentage is met.Scaling and target-service capacity
Watch adapter CPU and allocation rate alongside target read/write capacity, partition hot spots and connection/session limits. Scale adapter replicas on outstanding work, not QPS alone: a 100-item scan and a GetItem differ substantially. Tensor9 is responsible for autoscaling within the agreed per-operation concurrency, item-size, page and burst limits. The customer selects and sizes the target, including Cosmos RU/s, Spanner capacity or SQL connections; scaling the adapter cannot remove a hot partition or a database quota. Tell Tensor9 the expected steady rate, bursts, concurrency, payload sizes and operation mix. Tensor9 sizes and scales the adapter for the agreed load; you choose and monitor the target service’s capacity with Tensor9’s help. A latency budget is not a requests-per-second rating. Larger requests and higher rates need explicit terms, not silent inheritance of a small-request SLA.Data and behavior guarantees
Conditional writes must not silently lose their condition, and a transaction must not report atomic success after a partial commit. Exact number representation, consistency, secondary-index behavior and stream ordering remain those documented for this target. A request outside that support is rejected or handled as explicitly documented, not made correct by meeting a latency percentile. The underlying database’s durability commitment is not a Tensor9 storage SLA.Example and diagnosis
Inorders, GetItem for a 3 KiB item uses the point-read row. Query that examines 90 items but returns only two still uses the page row. An UpdateItem with a version condition uses the conditional-write row. In Explain, compare adapter expression/planning/serialization work with the measured target operation; a rise in Cosmos throttling or Spanner execution time is different from a rise in adapter queueing or catalog lookups.
Use tensor9 explain and the documented explain headers to understand the selected adapter and its behavior. Correlate available request diagnostics with the target provider’s latency, throttling and capacity metrics. An explain report helps diagnose a request; it is not by itself a qualified SLA timing measurement. Share the operation, request shape, timestamps and request identifiers with support, with credentials and customer payloads removed.
DynamoDB to Provisioned Cosmos DB
ConditionExpression or legacy Expected, no returned old item (ReturnValues absent or NONE), and streams disabled. The index configuration must be covered by your agreement. Size limits include the full current item and any previous item the adapter must read. For a delete that does not read the old item, count the key and request size. Writes with streams enabled need a separate latency agreement. Table management, PartiQL and Streams operations are not covered here. Any smaller API limit still applies.
Scaling limits. Tensor9 automatically adds adapter capacity within the traffic growth, burst size and infrastructure limits in your agreement. The standard service level does not promise a fixed request rate or unlimited scaling. Capacity depends on request sizes and types, how traffic is distributed across keys or message groups, target configuration and spare capacity for failures. More adapter processes cannot speed up every shared or sequential step. You remain responsible for target-service capacity; failures caused independently by the provider are outside this SLA.
Read the details. Each linked service page lists the covered operations, request limits, measurement rules, data guarantees, scaling limits and examples. This summary does not add coverage beyond those terms. Your signed agreement determines the service levels that apply to your deployment.
Why these latency targets differ
Plain GetItem, PutItem and DeleteItem have a 1 ms target for the small-item shape. Plain writes exclude conditions, old-value returns, secondary-index maintenance and streams. Update/conditional requests have 5 ms because the implementation may select PATCH, a partition-scoped stored procedure or an ETag-guarded read/modify/write path. Expressions are bounded to 2 KiB and 20 clauses, with at most two maintained indexes. Query/Scan has 10 ms for a page of at most 100 examined items and 400 KiB; item batches have 20 ms for at most 100 items, subject to each API’s smaller limit. Native Cosmos document execution is measured separately. Residual filtering, retries, response conversion and adapter-owned metadata remain fabric work. The adapter target does not imply Cosmos returns in 1 ms or that provisioned-account terms apply to a serverless account. Conditional conflicts and throttling still require correct handling, even when they move a request outside a tightly bounded latency class.Adapter and scope
These standard terms cover the DynamoDB table API adapted to provisioned Azure Cosmos DB. They do not apply interchangeably to a serverless Cosmos DB target or the Cosmos DB queue adapter. Your signed agreement determines the Cosmos DB consistency setting, capacity and partition configuration, deployment requirements, and covered request sizes and traffic levels.Operations and latency
Availability covers exactlyGetItem, PutItem, DeleteItem, UpdateItem, Query, Scan, BatchGetItem and BatchWriteItem, with the request options supported by the adapter. It also covers supported requests larger than the latency rows’ size limits.
TransactWriteItems, TransactGetItems and ExecuteTransaction are outside this adapter’s supported transaction scope and have no SLA here. Table lifecycle, PartiQL and DynamoDB Streams operations are not covered by these terms. A supported ExecuteStatement or BatchExecuteStatement does not inherit another operation’s SLA because it performs related item work.
Which writes are covered
A plain write has noConditionExpression or legacy Expected condition, ReturnValues absent or NONE, streams disabled, and the indexes specified in the agreement. Conditional writes and writes requesting supported previous-item values use the conditional-update class. UpdateItem uses that class regardless of how short its update expression looks.
Count the full items the adapter reads or changes, including previous items loaded to check conditions or return old values. Returning only a few fields through a DynamoDB projection does not make a larger item meet the size limit. For a plain delete that does not read the old item, the 4 KiB limit applies to the key and request.
Writes with streams enabled, and other supported request options outside these limits, need separately agreed latency targets. Sharing an operation name does not give them the same guarantee.
Which queries and batches are covered
To check whether a query meets the latency limits, record whether it reads the base table, an LSI or a GSI, its consistency mode, the items examined, and the data the adapter loaded. Filtering can discard many items before returning a small page. A small result does not prove that the request met those limits. Each batch API retains its own smaller item and payload limits. Preserve per-item outcomes and unprocessed entries. A batch response is one API result, not proof that every submitted read or write succeeded.Timing and responsibility
Adapter processing time includes authorization, encoding, expression processing, local queues, retries, coordination and response transformation. Native stored-procedure execution and attributable provider waits are measured separately. That timing separation does not remove responsibility for Tensor9-authored behavior executing at the target. An incorrect stored procedure, bad mapping or unnecessary expensive request remains an adapter issue even when Azure reports the resulting error or execution time. A correctly reported failed condition is healthy request handling. Returning success too early, losing a response, or making the wrong change is an adapter failure. After a timeout, the write may have succeeded. Do not claim it failed unless that has been established.Durability and consistency
The adapter may return success only after Cosmos DB has committed the change within its partition and the adapter has saved the required metadata or pending follow-up work. A supported condition check and its change must succeed or fail together within the scope the adapter supports. Keeping changes within one partition atomic does not imply support for DynamoDB multi-item transactions. No availability percentage permits the adapter to silently weaken a condition, lose adapter state already reported as saved or corrupt an item.Scaling and target sizing
The standard production model automatically adds adapter capacity within the agreement’s workload limits. Delays in adding capacity within those limits still count toward adapter latency. Provisioned Cosmos DB still needs an appropriate RU allocation, consistency mode and partition distribution. Record whether capacity uses manual or provider autoscale RU/s and which logical tables share a container. The same RU allocation does not guarantee the same origin-operation rate for every workload. Independent partitions can support parallel work. Hot partitions, shared container consumers, local expression processing, retry amplification and stream-writer ownership can constrain completed operations. More adapter instances cannot create more target RUs or remove per-key serialization. No numerical maximum request rate is assigned here. A supported limit needs the exact mix, item and expression sizes, index and stream settings, key distribution, target capacity and partition configuration, allowed traffic bursts and spare capacity for failures. It must measure useful completed origin operations, not a growing number of native retry attempts.Worked example: update an order
Theorders table receives an UpdateItem with a condition on its current version. The full item and expression fit the conditional-update class.
- The adapter interprets the condition and prepares the supported partition-local mutation. This preparation is adapter work.
- Cosmos DB executes the native mutation. Native execution time and request charge help explain target cost and delay.
- The adapter returns the origin-shaped result. Local retry and response handling remain part of the conditional-update adapter latency target.
Worked example: throttling during a traffic increase
Suppose 429 responses increase. Inspect RU consumption, partition pressure and competing workloads in the shared container. Then compare native calls per completed update, local retry delays and the selected mutation path. Target undersizing can require a capacity or workload change. If the adapter issues unnecessary requests or ignores supported tuning, the resulting pressure remains a Tensor9 issue. An Azure 429 response alone does not tell you whether Azure capacity or adapter behavior caused the problem. If a base read sees the committed item but a GSI does not, inspect index lag and mapping separately from throttling. Do not blindly repeat the write to make the index catch up.Evidence for support
Keep the operation, table and index path, account consistency, configured RU mode, full item and expression sizes, request charge where available, status, identifiers and incident timestamps. Include relevant shared-container and hot-partition observations, with recent tuning changes. Usetensor9 explain for profile behavior and a safely captured request report for observed mapping. x-t9-explain: true executes the operation; do not replay a conditional mutation just to gather a report. An explanation is not proof that a write committed, or a continuous measurement of SLA compliance.
Remove tokens, keys, credentials and sensitive item values before sharing evidence. Tensor9 helps separate target pressure, mapping behavior and adapter processing without requiring you to prove fault first.
DynamoDB to Azure Cosmos DB (serverless)
What this adapter does
Forazure::1.0.0::cosmosdb::serverless, Cosmos stores typed items in documents. Updates may use conditional PATCH, a partition-scoped stored procedure, or an ETag-guarded read/modify/write. Query windows and partition boundaries matter. Provisioned and serverless accounts retain their distinct throughput and index restrictions. The 1 ms point-operation objective is deliberately narrow. A conditional write, scanned page, transaction or control-plane request uses its own row. Stored procedures or SQL that implement the application operation are target execution; adapter catalog, coordination and retry work must not be mislabeled as application-database wait.
How the latency targets were chosen
Small point reads: 1 ms monthly p99.GetItem. Key decoding, one physical-plan construction and bounded item conversion. The target database’s own response time is separate.
Plain small-item writes: 1 ms monthly p99. DeleteItem, PutItem. The simple write avoids expression evaluation, read/modify/write and index/outbox amplification.
Conditional writes and updates: 5 ms monthly p99. DeleteItem, PutItem, UpdateItem. Expression parsing, update evaluation and result construction add CPU work; guarded updates can repeat local work after target conflicts.
Bounded query and scan pages: 10 ms monthly p99. Query, Scan. Physical query planning, item decoding, filters, ordering and cursor generation scale with the examined page, including rows the response omits.
Bounded item batches: 10 ms monthly p99. BatchGetItem, BatchWriteItem. The adapter builds and schedules item plans and assembles partial results; target-call fan-out is not free even when target waits are excluded.
Bounded PartiQL statements: 10 ms monthly p99. BatchExecuteStatement, ExecuteStatement. PartiQL adds parse, validate and lowering stages before ordinary item execution; a statement is not automatically a point lookup.
DynamoDB Streams reads: 10 ms monthly p99. DescribeStream, GetRecords, GetShardIterator, ListStreams. The adapter reads its stream/outbox representation and converts records, versions and cursors. Adapter-owned stream metadata waits remain on the clock.
Table and configuration API responses: 20 ms monthly p99. CreateTable, DeleteTable, DescribeContinuousBackups, DescribeEndpoints, DescribeLimits, DescribeTable, DescribeTimeToLive, ListTables, ListTagsOfResource, TagResource, UntagResource, UpdateContinuousBackups, UpdateTable, UpdateTimeToLive. Logical-table catalogs and lifecycle state must be persisted and validated. Their storage latency is adapter work even when the catalog uses the same database as application items.
Your signed agreement sets the terms for your deployment. A target does not add an operation or option that the compatibility tables mark unavailable.
What counts toward latency
For a request-response row, measure from the agreed ingress boundary to dispatch of the complete response. A row that explicitly names a first response chunk ends at that chunk; its number does not cover the rest of the stream. A long-poll row names the intentional wait and when adapter delay starts. Include parsing, authorization, admission, translation, serialization, adapter-owned storage and coordination, retries and response handling. Subtract only separately measured target-workload waits and external network segments allowed by the measurement rules. The adapter’s own response handling and dispatch remain covered. A database used for adapter metadata is still adapter work, even if a cloud provider hosts it. For concurrent calls, exclude the union of permitted wait intervals, not the sum of overlapping spans. Calculate each request’s adapter duration first, then the monthly p99. Do not subtract one service’s p99 from another’s. Known adapter timeouts are over-budget samples; failed or incomplete requests cannot disappear to improve the percentile. Missing measurements do not become zero latency. An SDK call span alone does not prove how much of its duration can be excluded.Availability and failures
The 99.9% request target measures correct adapter handling, not the percentage of application calls that return success. Correctly forwarding a target quota or permission error is different from producing that error because the adapter sent the wrong request. Adapter-caused failures count even when the target is healthy. With 1,000,000 eligible calls in a month, a 99.9% target permits at most 1,000 adapter-attributable failures. Endpoint probes have their own denominator. Correctness defects remain actionable even when the monthly availability percentage is met.Scaling and target-service capacity
Watch adapter CPU and allocation rate alongside target read/write capacity, partition hot spots and connection/session limits. Scale adapter replicas on outstanding work, not QPS alone: a 100-item scan and a GetItem differ substantially. Tensor9 is responsible for autoscaling within the agreed per-operation concurrency, item-size, page and burst limits. The customer selects and sizes the target, including Cosmos RU/s, Spanner capacity or SQL connections; scaling the adapter cannot remove a hot partition or a database quota. Tell Tensor9 the expected steady rate, bursts, concurrency, payload sizes and operation mix. Tensor9 sizes and scales the adapter for the agreed load; you choose and monitor the target service’s capacity with Tensor9’s help. A latency budget is not a requests-per-second rating. Larger requests and higher rates need explicit terms, not silent inheritance of a small-request SLA.Data and behavior guarantees
Conditional writes must not silently lose their condition, and a transaction must not report atomic success after a partial commit. Exact number representation, consistency, secondary-index behavior and stream ordering remain those documented for this target. A request outside that support is rejected or handled as explicitly documented, not made correct by meeting a latency percentile. The underlying database’s durability commitment is not a Tensor9 storage SLA.Example and diagnosis
Inorders, GetItem for a 3 KiB item uses the point-read row. Query that examines 90 items but returns only two still uses the page row. An UpdateItem with a version condition uses the conditional-write row. In Explain, compare adapter expression/planning/serialization work with the measured target operation; a rise in Cosmos throttling or Spanner execution time is different from a rise in adapter queueing or catalog lookups.
Use tensor9 explain and the documented explain headers to understand the selected adapter and its behavior. Correlate available request diagnostics with the target provider’s latency, throttling and capacity metrics. An explain report helps diagnose a request; it is not by itself a qualified SLA timing measurement. Share the operation, request shape, timestamps and request identifiers with support, with credentials and customer payloads removed.
DynamoDB to Cloud Bigtable
What this adapter does
Forgoogle::1.0.0::bigtable, Items use row-atomic Bigtable storage. Multi-item transactions and unsupported secondary-index/stream semantics do not become covered merely because point reads are covered. The 1 ms point-operation objective is deliberately narrow. A conditional write, scanned page, transaction or control-plane request uses its own row. Stored procedures or SQL that implement the application operation are target execution; adapter catalog, coordination and retry work must not be mislabeled as application-database wait.
How the latency targets were chosen
Small point reads: 1 ms monthly p99.GetItem. Key decoding, one physical-plan construction and bounded item conversion. The target database’s own response time is separate.
Plain small-item writes: 1 ms monthly p99. DeleteItem, PutItem. The simple write avoids expression evaluation, read/modify/write and index/outbox amplification.
Conditional writes and updates: 3 ms monthly p99. DeleteItem, PutItem, UpdateItem. Expression parsing, update evaluation and result construction add CPU work; guarded updates can repeat local work after target conflicts.
Bounded query and scan pages: 5 ms monthly p99. Query, Scan. Physical query planning, item decoding, filters, ordering and cursor generation scale with the examined page, including rows the response omits.
Bounded item batches: 10 ms monthly p99. BatchGetItem, BatchWriteItem. The adapter builds and schedules item plans and assembles partial results; target-call fan-out is not free even when target waits are excluded.
Table and configuration API responses: 20 ms monthly p99. CreateTable, DeleteTable, DescribeTable, ListTables, UpdateTable. Logical-table catalogs and lifecycle state must be persisted and validated. Their storage latency is adapter work even when the catalog uses the same database as application items.
Your signed agreement sets the terms for your deployment. A target does not add an operation or option that the compatibility tables mark unavailable.
What counts toward latency
For a request-response row, measure from the agreed ingress boundary to dispatch of the complete response. A row that explicitly names a first response chunk ends at that chunk; its number does not cover the rest of the stream. A long-poll row names the intentional wait and when adapter delay starts. Include parsing, authorization, admission, translation, serialization, adapter-owned storage and coordination, retries and response handling. Subtract only separately measured target-workload waits and external network segments allowed by the measurement rules. The adapter’s own response handling and dispatch remain covered. A database used for adapter metadata is still adapter work, even if a cloud provider hosts it. For concurrent calls, exclude the union of permitted wait intervals, not the sum of overlapping spans. Calculate each request’s adapter duration first, then the monthly p99. Do not subtract one service’s p99 from another’s. Known adapter timeouts are over-budget samples; failed or incomplete requests cannot disappear to improve the percentile. Missing measurements do not become zero latency. An SDK call span alone does not prove how much of its duration can be excluded.Availability and failures
The 99.9% request target measures correct adapter handling, not the percentage of application calls that return success. Correctly forwarding a target quota or permission error is different from producing that error because the adapter sent the wrong request. Adapter-caused failures count even when the target is healthy. With 1,000,000 eligible calls in a month, a 99.9% target permits at most 1,000 adapter-attributable failures. Endpoint probes have their own denominator. Correctness defects remain actionable even when the monthly availability percentage is met.Scaling and target-service capacity
Watch adapter CPU and allocation rate alongside target read/write capacity, partition hot spots and connection/session limits. Scale adapter replicas on outstanding work, not QPS alone: a 100-item scan and a GetItem differ substantially. Tensor9 is responsible for autoscaling within the agreed per-operation concurrency, item-size, page and burst limits. The customer selects and sizes the target, including Cosmos RU/s, Spanner capacity or SQL connections; scaling the adapter cannot remove a hot partition or a database quota. Tell Tensor9 the expected steady rate, bursts, concurrency, payload sizes and operation mix. Tensor9 sizes and scales the adapter for the agreed load; you choose and monitor the target service’s capacity with Tensor9’s help. A latency budget is not a requests-per-second rating. Larger requests and higher rates need explicit terms, not silent inheritance of a small-request SLA.Data and behavior guarantees
Conditional writes must not silently lose their condition, and a transaction must not report atomic success after a partial commit. Exact number representation, consistency, secondary-index behavior and stream ordering remain those documented for this target. A request outside that support is rejected or handled as explicitly documented, not made correct by meeting a latency percentile. The underlying database’s durability commitment is not a Tensor9 storage SLA.Example and diagnosis
Inorders, GetItem for a 3 KiB item uses the point-read row. Query that examines 90 items but returns only two still uses the page row. An UpdateItem with a version condition uses the conditional-write row. In Explain, compare adapter expression/planning/serialization work with the measured target operation; a rise in Cosmos throttling or Spanner execution time is different from a rise in adapter queueing or catalog lookups.
Use tensor9 explain and the documented explain headers to understand the selected adapter and its behavior. Correlate available request diagnostics with the target provider’s latency, throttling and capacity metrics. An explain report helps diagnose a request; it is not by itself a qualified SLA timing measurement. Share the operation, request shape, timestamps and request identifiers with support, with credentials and customer payloads removed.
DynamoDB to Cloud SQL for PostgreSQL
What this adapter does
Forgoogle::1.0.0::cloudsql::postgresql, The SQL-backed adapter maps items, expressions and indexes onto relational rows and transactions. Row locks, index maintenance, stream outboxes and transaction conflict handling can add work beyond a single statement. The 1 ms point-operation objective is deliberately narrow. A conditional write, scanned page, transaction or control-plane request uses its own row. Stored procedures or SQL that implement the application operation are target execution; adapter catalog, coordination and retry work must not be mislabeled as application-database wait.
How the latency targets were chosen
Small point reads: 1 ms monthly p99.GetItem. Key decoding, one physical-plan construction and bounded item conversion. The target database’s own response time is separate.
Plain small-item writes: 1 ms monthly p99. DeleteItem, PutItem. The simple write avoids expression evaluation, read/modify/write and index/outbox amplification.
Conditional writes and updates: 3 ms monthly p99. DeleteItem, PutItem, UpdateItem. Expression parsing, update evaluation and result construction add CPU work; guarded updates can repeat local work after target conflicts.
Bounded query and scan pages: 5 ms monthly p99. Query, Scan. Physical query planning, item decoding, filters, ordering and cursor generation scale with the examined page, including rows the response omits.
Bounded transactions: 10 ms monthly p99. TransactWriteItems. Transaction validation, conditional plans, idempotency checks and commit-result assembly cost more than independent point operations.
DynamoDB Streams reads: 10 ms monthly p99. DescribeStream, GetRecords, GetShardIterator, ListStreams. The adapter reads its stream/outbox representation and converts records, versions and cursors. Adapter-owned stream metadata waits remain on the clock.
Your signed agreement sets the terms for your deployment. A target does not add an operation or option that the compatibility tables mark unavailable.
What counts toward latency
For a request-response row, measure from the agreed ingress boundary to dispatch of the complete response. A row that explicitly names a first response chunk ends at that chunk; its number does not cover the rest of the stream. A long-poll row names the intentional wait and when adapter delay starts. Include parsing, authorization, admission, translation, serialization, adapter-owned storage and coordination, retries and response handling. Subtract only separately measured target-workload waits and external network segments allowed by the measurement rules. The adapter’s own response handling and dispatch remain covered. A database used for adapter metadata is still adapter work, even if a cloud provider hosts it. For concurrent calls, exclude the union of permitted wait intervals, not the sum of overlapping spans. Calculate each request’s adapter duration first, then the monthly p99. Do not subtract one service’s p99 from another’s. Known adapter timeouts are over-budget samples; failed or incomplete requests cannot disappear to improve the percentile. Missing measurements do not become zero latency. An SDK call span alone does not prove how much of its duration can be excluded.Availability and failures
The 99.9% request target measures correct adapter handling, not the percentage of application calls that return success. Correctly forwarding a target quota or permission error is different from producing that error because the adapter sent the wrong request. Adapter-caused failures count even when the target is healthy. With 1,000,000 eligible calls in a month, a 99.9% target permits at most 1,000 adapter-attributable failures. Endpoint probes have their own denominator. Correctness defects remain actionable even when the monthly availability percentage is met.Scaling and target-service capacity
Watch adapter CPU and allocation rate alongside target read/write capacity, partition hot spots and connection/session limits. Scale adapter replicas on outstanding work, not QPS alone: a 100-item scan and a GetItem differ substantially. Tensor9 is responsible for autoscaling within the agreed per-operation concurrency, item-size, page and burst limits. The customer selects and sizes the target, including Cosmos RU/s, Spanner capacity or SQL connections; scaling the adapter cannot remove a hot partition or a database quota. Tell Tensor9 the expected steady rate, bursts, concurrency, payload sizes and operation mix. Tensor9 sizes and scales the adapter for the agreed load; you choose and monitor the target service’s capacity with Tensor9’s help. A latency budget is not a requests-per-second rating. Larger requests and higher rates need explicit terms, not silent inheritance of a small-request SLA.Data and behavior guarantees
Conditional writes must not silently lose their condition, and a transaction must not report atomic success after a partial commit. Exact number representation, consistency, secondary-index behavior and stream ordering remain those documented for this target. A request outside that support is rejected or handled as explicitly documented, not made correct by meeting a latency percentile. The underlying database’s durability commitment is not a Tensor9 storage SLA.Example and diagnosis
Inorders, GetItem for a 3 KiB item uses the point-read row. Query that examines 90 items but returns only two still uses the page row. An UpdateItem with a version condition uses the conditional-write row. In Explain, compare adapter expression/planning/serialization work with the measured target operation; a rise in Cosmos throttling or Spanner execution time is different from a rise in adapter queueing or catalog lookups.
Use tensor9 explain and the documented explain headers to understand the selected adapter and its behavior. Correlate available request diagnostics with the target provider’s latency, throttling and capacity metrics. An explain report helps diagnose a request; it is not by itself a qualified SLA timing measurement. Share the operation, request shape, timestamps and request identifiers with support, with credentials and customer payloads removed.
DynamoDB to Firestore
ConditionExpression or legacy Expected, no returned old item (ReturnValues absent or NONE), and streams disabled. The index configuration must be covered by your agreement. Size limits include the full current item and any previous item the adapter must read. For a delete that does not read the old item, count the key and request size. Writes with streams enabled need a separate latency agreement. Table management, PartiQL and Streams operations are not covered here. Any smaller API limit still applies.
Scaling limits. Tensor9 automatically adds adapter capacity within the traffic growth, burst size and infrastructure limits in your agreement. The standard service level does not promise a fixed request rate or unlimited scaling. Capacity depends on request sizes and types, how traffic is distributed across keys or message groups, target configuration and spare capacity for failures. More adapter processes cannot speed up every shared or sequential step. You remain responsible for target-service capacity; failures caused independently by the provider are outside this SLA.
Read the details. Each linked service page lists the covered operations, request limits, measurement rules, data guarantees, scaling limits and examples. This summary does not add coverage beyond those terms. Your signed agreement determines the service levels that apply to your deployment.
Why these latency targets differ
Plain point requests have a 1 ms target for items up to 4 KiB, with at most 64 attributes and nesting depth 8. Plain writes have no condition, old-value return, secondary-index maintenance or stream work. The 3 ms conditional/update class adds expression parsing and bounded item manipulation; it permits at most 20 expression clauses and two maintained indexes. The 10 ms page class accounts for decoding and filtering up to 100 examined items, including discarded items. A transaction with up to 100 actions has a separate 20 ms budget for validation, planning and result handling. Target document execution is measured separately; adapter-owned catalog, coordination, retry and response work remains included. Changing the request shape changes its class rather than quietly raising the point-request limit.Adapter and scope
These standard terms cover the DynamoDB table API adapted to Google Cloud Firestore. They distinguish the adapter’s processing from Firestore execution, while keeping the adapter responsible for correct translation, acknowledgment and response handling. Your signed agreement determines which deployment is covered, where timing starts and stops, and which request sizes and traffic levels are covered.Operations and latency
The availability service level covers exactlyGetItem, PutItem, DeleteItem, UpdateItem, Query, Scan and TransactWriteItems, with the request options supported by the adapter. Availability is not restricted to the small payloads used to qualify the numerical latency terms.
BatchGetItem, BatchWriteItem and TransactGetItems are not covered by these standard terms. Table lifecycle, PartiQL and DynamoDB Streams operations are also outside these terms. Absence from this SLA is not a statement that an operation is unsupported; consult the directed service profile for support.
Plain writes and conditional updates
A plainPutItem or DeleteItem has no ConditionExpression or legacy Expected condition, has ReturnValues absent or NONE, uses the index configuration specified in the agreement, and has streams disabled.
A request that checks a supported condition or asks for supported values from the previous item needs more work. It belongs in the conditional-update class, not the plain-write class. UpdateItem always belongs in the update class, even when it only changes one small attribute.
The item-size limit includes the complete item the adapter reads or changes, including any previous item needed to evaluate a condition. A DynamoDB projection returning 100 bytes does not bring a larger item the adapter loaded within that limit. For a plain delete that does not read the old item, the 4 KiB bound applies to the key and request instead.
Writes with streams enabled, and other supported request options outside these limits, need separately agreed latency targets. They do not inherit these latency values merely because the operation name is the same.
Queries and transactions
Record whether a query reads the base table, an LSI or a GSI, along with its consistency mode and declared indexes. A filter returning five results after examining thousands of candidates does not meet the query row’s limits. The transaction class covers only the combinations described by this adapter’s profile. The performance-class limit does not extend API limits or add support for stream-enabled transactions. A supported request that exceeds these limits has no latency target from this row. The adapter must not truncate its result to meet that target.What the latency includes
Included work covers permission checks, reading the request, processing expressions, accepting or queueing the request, local retries, coordination, and preparing the response. Firestore transaction and commit waits are separately measured when measurements reliably show how long Firestore took. Local retry delays remain adapter time even when contention triggered them. A timing span named after Firestore is not sufficient evidence that all time inside it was spent waiting on Firestore. A correctConditionalCheckFailedException is a valid result, not an availability failure. Evaluating the condition incorrectly, losing the response, or returning success for a failed write is an adapter failure.
Durability and consistency
The adapter must handle data correctly even when it meets the availability target:- Return success for a write only after the required Firestore commit and adapter-state updates.
- Keep a supported condition check and its write together, and ensure supported transactions either complete all their changes or make none.
- Preserve the profile’s supported numeric domain and reject unsupported numeric values rather than silently rounding them.
- Enforce the 400 KiB item limit. This API limit is separate from the smaller 4 KiB limit for the latency target.
- Honor the declared base-table and index behavior rather than substituting an unrestricted scan or an unchecked write.
Scaling and limits
In the standard production model, Tensor9 automatically adds adapter capacity within the agreement’s workload limits. Your team is not responsible for routinely adjusting the number of adapter instances. Delays in adding capacity within those limits still count toward adapter latency. Independent keys can supply parallel work. A heavily contended document, shared coordination stage or table-scoped stream-writer ownership can limit scale even when more workers are available. Firestore quotas and target contention are distinct from time spent processing expressions, queueing requests, and retrying. The standard terms do not set a numerical maximum request rate. A useful agreed limit must identify the operation mix, item and expression sizes, indexes, consistency, streams, key distribution, allowed traffic bursts and spare capacity for failures. It measures completed origin operations while preserving latency and correctness, not just requests sent toward Firestore. Do not add separately measured read and update maxima together. Both operations can share workers and state, while conditional updates do substantially more work per request.Worked example: conditional order update
Theorders table stores a small order with a version attribute. An application uses UpdateItem to change its status only if the stored version matches the version it read.
- The adapter decodes the expression and prepares the supported Firestore operation. This is adapter work.
- Firestore evaluates the native transaction and commits the change, or reports a conflict. The separately measured time spent waiting for the target is recorded separately.
- The adapter returns the DynamoDB-shaped success or conditional failure. Local retry and response work remain covered.
Worked example: one hot order
Suppose many workers update the same order and p99 response time rises. Compare Firestore contention, key distribution, local queueing and retries for the same interval. If native contention increases while local processing stays stable, changing the workload’s contention pattern can be more effective than adding adapter instances. If retries multiply native calls or a local queue grows while Firestore has headroom, Tensor9 investigates the adapter behavior. Both conditions can occur together; a target conflict is not a blanket exclusion.Evidence for support
Keep the operation, table and index selection, consistency mode, full item and expression sizes, examined candidate count, status, timestamps and request identifiers. Record index or stream configuration changes that preceded the incident. Usetensor9 explain to inspect the directed profile. A request-level Explain report can help relate selected behavior to observed calls; it is not a continuous measurement of SLA compliance. x-t9-explain: true executes the request while recording an explanation, so do not replay an order mutation merely to obtain a report.
Share sanitized evidence through the agreed support channel. Remove credentials, tokens and sensitive item values while preserving the shape, sizes and identifiers needed to correlate the incident. Tensor9 helps investigate both adapter and target behavior; you do not need to prove fault before contacting support.
DynamoDB to Spanner
ConditionExpression or legacy Expected, no returned old item (ReturnValues absent or NONE), and streams disabled. The index configuration must be covered by your agreement. Size limits include the full current item and any previous item the adapter must read. For a delete that does not read the old item, count the key and request size. Writes with streams enabled need a separate latency agreement. Table management, PartiQL and Streams operations are not covered here. Any smaller API limit still applies.
Scaling limits. Tensor9 automatically adds adapter capacity within the traffic growth, burst size and infrastructure limits in your agreement. The standard service level does not promise a fixed request rate or unlimited scaling. Capacity depends on request sizes and types, how traffic is distributed across keys or message groups, target configuration and spare capacity for failures. More adapter processes cannot speed up every shared or sequential step. You remain responsible for target-service capacity; failures caused independently by the provider are outside this SLA.
Read the details. Each linked service page lists the covered operations, request limits, measurement rules, data guarantees, scaling limits and examples. This summary does not add coverage beyond those terms. Your signed agreement determines the service levels that apply to your deployment.
Why these latency targets differ
GetItem and plain small writes each have a 1 ms target. A plain write avoids conditions, old-value returns, secondary-index maintenance and streams. The conditional/update class has 3 ms for bounded expression work and physical-plan construction; a bounded query/scan page has 5 ms for up to 100 examined items and 400 KiB decoded data. Batches and transactions retain a separate 20 ms budget for up to 100 actions/items, subject to the smaller limit of each API. Only separately measured Spanner application-operation waits are candidates for exclusion. Adapter metadata and coordination stored in Spanner remain adapter work.Adapter and scope
These standard terms cover the DynamoDB table API adapted to Google Cloud Spanner. The adapter commitment concerns correct handling and the processing it adds; it is not a guarantee that a complete Spanner transaction finishes within the adapter’s latency budget. Your signed agreement determines the deployment requirements and the request sizes, traffic levels, and traffic bursts it covers.Operations and latency
Availability covers exactly the operations in the table with the request options supported by the adapter, not only requests inside the latency row’s size and count limits. Table lifecycle, PartiQL and DynamoDB Streams operations are not covered by these terms. This profile does not provide DynamoDB Streams support. An equal threshold does not combine measurements: reportTransactGetItems and TransactWriteItems separately, just as successful high-volume reads must not hide failing writes.
Which write class applies?
The plain-write class requires noConditionExpression or legacy Expected condition, ReturnValues absent or NONE, streams disabled, and the index configuration specified in the agreement.
A supported condition or supported previous-item return puts PutItem and DeleteItem in the conditional-update class. UpdateItem always uses that class. The request determines which row applies. A faster execution path does not let the adapter choose a different row afterward.
The 4 KiB limit applies to the full items the adapter reads, loads, or changes, including any previous item needed for a condition or response. Returning only a few fields through a DynamoDB projection does not make a larger item qualify. For a plain delete that does not load the old item, measure the key and request size instead.
Pages, batches and transactions
For a query, record the base-table or index path, consistency choice and examined data. A page returning ten items does not meet the query limit if the adapter had to scan many more items before filtering them. A batch’s API-specific item limit still applies even though the shared performance class says “at most 100.” Preserve individual item outcomes and unprocessed items rather than treating an HTTP success as proof that every item completed. The transaction performance class is narrower than some supported API maxima. Supported combinations and idempotency-token behavior remain part of correctness; a request is not allowed to lose atomicity to fit the latency class.What counts toward adapter latency
Include authorization, decoding, expression evaluation, mutation preparation, local queueing, connection or session acquisition, coordination, retry scheduling and response handling. These costs remain adapter work even when they occur inside a function that calls Spanner. Time spent waiting for Spanner to execute and commit a request is reported separately when it can be measured. Measure the adapter and target portions of the same request. Subtracting the p99 of one benchmark from the p99 of another does not tell you how much time the adapter added. Correctly reporting a failed condition is a valid result. If the write commits but the adapter loses the response, the caller did not receive a successful response. Check whether repeating the operation is safe before retrying.Durability and consistency
The standard obligations include:- Return success for writes only after the required Spanner and adapter commits.
- Preserve data reported as successfully saved when the adapter recovers its state.
- Preserve supported decimal values exactly and enforce the 400 KiB item limit.
- Keep supported multi-item transactions atomic and preserve documented idempotency behavior.
- Provide the documented strong reads from the base table and update native indexes as part of the same commit.
ConsistentRead=true simply because Spanner can perform strong reads. The adapter must preserve the supported origin request rules.
These are correctness obligations, not an allowance to corrupt a small percentage of records while meeting the availability target. Native storage durability remains a separate provider responsibility.
Scaling and limits
The standard production model automatically adds adapter capacity. The agreed limits must describe how many application operations can complete for the actual workload, including adapter work before and between target calls. Independent transactions and keys can supply parallel work. Shared connection and session budgets, hot rows, local expression processing and repeated conflicts can limit useful completions. Adding replicas without a fleet-wide connection budget can move the bottleneck or make contention worse. The standard terms do not assign a numerical maximum request rate. A point-read limit cannot be multiplied by the number of actions in a transaction to establish transaction capacity. Qualify the transaction mix, action count, item sizes, indexes, conflict distribution, traffic growth and spare capacity for failures separately. The customer’s Spanner sizing affects native execution capacity. Tensor9 remains responsible for unnecessary repeated work and local queueing within the agreed adapter workload limits; “increase Spanner capacity” is not an adequate answer when the delay is in a local pool.Worked example: order and inventory transaction
The application usesTransactWriteItems to create an order and decrement its inventory item. The action count and all data loaded by the adapter meet the transaction row’s limits.
- The adapter validates the supported actions and prepares their native transaction. Authorization, expression and encoding work count as adapter processing time.
- Spanner executes and commits the transaction. Separately measured target wait is measured separately.
- The adapter constructs the origin response. The response must reflect the transaction’s atomic outcome.
Worked example: slow requests with spare target capacity
Suppose requests slow down while Spanner metrics show available capacity. Local session acquisition grows, and retries occupy workers for longer. Tensor9 investigates waits for a connection or session, total connections, retry scheduling and traffic mix. Increasing target capacity may not reduce those delays. Conversely, if native contention dominates after local queues are ruled out, support helps examine hot rows, transaction scope and target sizing. If a transaction times out, it may already have committed. Check what happened before retrying. Do not repeat it with a new identity on the assumption that the first attempt did nothing.Evidence for support
Capture operation names, transaction action counts, full item and expression sizes, indexes, consistency, result classes, request identifiers and the incident interval. Keep local queue, pool, retry and native execution observations together. An Explain report can help identify the selected path and captured calls, but it does not prove a commit that the report did not observe, and it does not continuously measure SLA compliance.x-t9-explain: true executes the requested operation; use it only when repeating that operation is safe, or capture it on an already intended request.
Remove tokens, credentials and sensitive item values from support material. Preserve sizes, conditions’ structure and correlation identifiers so Tensor9 can investigate without needing sensitive customer data or requiring you to prove who caused the problem.
DynamoDB to OCI NoSQL Database
SLA status: Not applicable The application uses the OCI NoSQL API on this mapping. It does not provide a DynamoDB request translator, so DynamoDB fabric latency does not apply.DynamoDB to PostgreSQL
What this adapter does
Forpostgres::1.0.0::database, The SQL-backed adapter maps items, expressions and indexes onto relational rows and transactions. Row locks, index maintenance, stream outboxes and transaction conflict handling can add work beyond a single statement. The 1 ms point-operation objective is deliberately narrow. A conditional write, scanned page, transaction or control-plane request uses its own row. Stored procedures or SQL that implement the application operation are target execution; adapter catalog, coordination and retry work must not be mislabeled as application-database wait.
How the latency targets were chosen
Small point reads: 1 ms monthly p99.GetItem. Key decoding, one physical-plan construction and bounded item conversion. The target database’s own response time is separate.
Plain small-item writes: 1 ms monthly p99. DeleteItem, PutItem. The simple write avoids expression evaluation, read/modify/write and index/outbox amplification.
Conditional writes and updates: 3 ms monthly p99. DeleteItem, PutItem, UpdateItem. Expression parsing, update evaluation and result construction add CPU work; guarded updates can repeat local work after target conflicts.
Bounded query and scan pages: 5 ms monthly p99. Query, Scan. Physical query planning, item decoding, filters, ordering and cursor generation scale with the examined page, including rows the response omits.
Bounded transactions: 10 ms monthly p99. TransactWriteItems. Transaction validation, conditional plans, idempotency checks and commit-result assembly cost more than independent point operations.
DynamoDB Streams reads: 10 ms monthly p99. DescribeStream, GetRecords, GetShardIterator, ListStreams. The adapter reads its stream/outbox representation and converts records, versions and cursors. Adapter-owned stream metadata waits remain on the clock.
Your signed agreement sets the terms for your deployment. A target does not add an operation or option that the compatibility tables mark unavailable.
What counts toward latency
For a request-response row, measure from the agreed ingress boundary to dispatch of the complete response. A row that explicitly names a first response chunk ends at that chunk; its number does not cover the rest of the stream. A long-poll row names the intentional wait and when adapter delay starts. Include parsing, authorization, admission, translation, serialization, adapter-owned storage and coordination, retries and response handling. Subtract only separately measured target-workload waits and external network segments allowed by the measurement rules. The adapter’s own response handling and dispatch remain covered. A database used for adapter metadata is still adapter work, even if a cloud provider hosts it. For concurrent calls, exclude the union of permitted wait intervals, not the sum of overlapping spans. Calculate each request’s adapter duration first, then the monthly p99. Do not subtract one service’s p99 from another’s. Known adapter timeouts are over-budget samples; failed or incomplete requests cannot disappear to improve the percentile. Missing measurements do not become zero latency. An SDK call span alone does not prove how much of its duration can be excluded.Availability and failures
The 99.9% request target measures correct adapter handling, not the percentage of application calls that return success. Correctly forwarding a target quota or permission error is different from producing that error because the adapter sent the wrong request. Adapter-caused failures count even when the target is healthy. With 1,000,000 eligible calls in a month, a 99.9% target permits at most 1,000 adapter-attributable failures. Endpoint probes have their own denominator. Correctness defects remain actionable even when the monthly availability percentage is met.Scaling and target-service capacity
Watch adapter CPU and allocation rate alongside target read/write capacity, partition hot spots and connection/session limits. Scale adapter replicas on outstanding work, not QPS alone: a 100-item scan and a GetItem differ substantially. Tensor9 is responsible for autoscaling within the agreed per-operation concurrency, item-size, page and burst limits. The customer selects and sizes the target, including Cosmos RU/s, Spanner capacity or SQL connections; scaling the adapter cannot remove a hot partition or a database quota. Tell Tensor9 the expected steady rate, bursts, concurrency, payload sizes and operation mix. Tensor9 sizes and scales the adapter for the agreed load; you choose and monitor the target service’s capacity with Tensor9’s help. A latency budget is not a requests-per-second rating. Larger requests and higher rates need explicit terms, not silent inheritance of a small-request SLA.Data and behavior guarantees
Conditional writes must not silently lose their condition, and a transaction must not report atomic success after a partial commit. Exact number representation, consistency, secondary-index behavior and stream ordering remain those documented for this target. A request outside that support is rejected or handled as explicitly documented, not made correct by meeting a latency percentile. The underlying database’s durability commitment is not a Tensor9 storage SLA.Example and diagnosis
Inorders, GetItem for a 3 KiB item uses the point-read row. Query that examines 90 items but returns only two still uses the page row. An UpdateItem with a version condition uses the conditional-write row. In Explain, compare adapter expression/planning/serialization work with the measured target operation; a rise in Cosmos throttling or Spanner execution time is different from a rise in adapter queueing or catalog lookups.
Use tensor9 explain and the documented explain headers to understand the selected adapter and its behavior. Correlate available request diagnostics with the target provider’s latency, throttling and capacity metrics. An explain report helps diagnose a request; it is not by itself a qualified SLA timing measurement. Share the operation, request shape, timestamps and request identifiers with support, with credentials and customer payloads removed.
DynamoDB to Scaleway Managed Database for PostgreSQL
What this adapter does
Forscaleway::1.0.0::rdb::postgresql, The SQL-backed adapter maps items, expressions and indexes onto relational rows and transactions. Row locks, index maintenance, stream outboxes and transaction conflict handling can add work beyond a single statement. The 1 ms point-operation objective is deliberately narrow. A conditional write, scanned page, transaction or control-plane request uses its own row. Stored procedures or SQL that implement the application operation are target execution; adapter catalog, coordination and retry work must not be mislabeled as application-database wait.
How the latency targets were chosen
Small point reads: 1 ms monthly p99.GetItem. Key decoding, one physical-plan construction and bounded item conversion. The target database’s own response time is separate.
Plain small-item writes: 1 ms monthly p99. DeleteItem, PutItem. The simple write avoids expression evaluation, read/modify/write and index/outbox amplification.
Conditional writes and updates: 3 ms monthly p99. DeleteItem, PutItem, UpdateItem. Expression parsing, update evaluation and result construction add CPU work; guarded updates can repeat local work after target conflicts.
Bounded query and scan pages: 5 ms monthly p99. Query, Scan. Physical query planning, item decoding, filters, ordering and cursor generation scale with the examined page, including rows the response omits.
Bounded transactions: 10 ms monthly p99. TransactGetItems, TransactWriteItems. Transaction validation, conditional plans, idempotency checks and commit-result assembly cost more than independent point operations.
Bounded PartiQL statements: 10 ms monthly p99. ExecuteStatement. PartiQL adds parse, validate and lowering stages before ordinary item execution; a statement is not automatically a point lookup.
Table and configuration API responses: 20 ms monthly p99. CreateTable, DeleteTable. Logical-table catalogs and lifecycle state must be persisted and validated. Their storage latency is adapter work even when the catalog uses the same database as application items.
Your signed agreement sets the terms for your deployment. A target does not add an operation or option that the compatibility tables mark unavailable.
What counts toward latency
For a request-response row, measure from the agreed ingress boundary to dispatch of the complete response. A row that explicitly names a first response chunk ends at that chunk; its number does not cover the rest of the stream. A long-poll row names the intentional wait and when adapter delay starts. Include parsing, authorization, admission, translation, serialization, adapter-owned storage and coordination, retries and response handling. Subtract only separately measured target-workload waits and external network segments allowed by the measurement rules. The adapter’s own response handling and dispatch remain covered. A database used for adapter metadata is still adapter work, even if a cloud provider hosts it. For concurrent calls, exclude the union of permitted wait intervals, not the sum of overlapping spans. Calculate each request’s adapter duration first, then the monthly p99. Do not subtract one service’s p99 from another’s. Known adapter timeouts are over-budget samples; failed or incomplete requests cannot disappear to improve the percentile. Missing measurements do not become zero latency. An SDK call span alone does not prove how much of its duration can be excluded.Availability and failures
The 99.9% request target measures correct adapter handling, not the percentage of application calls that return success. Correctly forwarding a target quota or permission error is different from producing that error because the adapter sent the wrong request. Adapter-caused failures count even when the target is healthy. With 1,000,000 eligible calls in a month, a 99.9% target permits at most 1,000 adapter-attributable failures. Endpoint probes have their own denominator. Correctness defects remain actionable even when the monthly availability percentage is met.Scaling and target-service capacity
Watch adapter CPU and allocation rate alongside target read/write capacity, partition hot spots and connection/session limits. Scale adapter replicas on outstanding work, not QPS alone: a 100-item scan and a GetItem differ substantially. Tensor9 is responsible for autoscaling within the agreed per-operation concurrency, item-size, page and burst limits. The customer selects and sizes the target, including Cosmos RU/s, Spanner capacity or SQL connections; scaling the adapter cannot remove a hot partition or a database quota. Tell Tensor9 the expected steady rate, bursts, concurrency, payload sizes and operation mix. Tensor9 sizes and scales the adapter for the agreed load; you choose and monitor the target service’s capacity with Tensor9’s help. A latency budget is not a requests-per-second rating. Larger requests and higher rates need explicit terms, not silent inheritance of a small-request SLA.Data and behavior guarantees
Conditional writes must not silently lose their condition, and a transaction must not report atomic success after a partial commit. Exact number representation, consistency, secondary-index behavior and stream ordering remain those documented for this target. A request outside that support is rejected or handled as explicitly documented, not made correct by meeting a latency percentile. The underlying database’s durability commitment is not a Tensor9 storage SLA.Example and diagnosis
Inorders, GetItem for a 3 KiB item uses the point-read row. Query that examines 90 items but returns only two still uses the page row. An UpdateItem with a version condition uses the conditional-write row. In Explain, compare adapter expression/planning/serialization work with the measured target operation; a rise in Cosmos throttling or Spanner execution time is different from a rise in adapter queueing or catalog lookups.
Use tensor9 explain and the documented explain headers to understand the selected adapter and its behavior. Correlate available request diagnostics with the target provider’s latency, throttling and capacity metrics. An explain report helps diagnose a request; it is not by itself a qualified SLA timing measurement. Share the operation, request shape, timestamps and request identifiers with support, with credentials and customer payloads removed.
Install and run
The documentation and SLAs are public. Downloading and running the Cloud Adapter binary requires an entitled customer account. SetT9_API_KEY as described in Install and Authenticate, then list the adapters your account may use with this origin: