An independent test suite that validates any DynamoDB-compatible endpoint against real DynamoDB behaviour. It works against DynamoDB, DynamoDB Local, Dynoxide, Dynoxide (wasm), Dynalite, LocalStack, ExtendDB, Floci, Ministack, or anything else that implements the DynamoDB HTTP API.
There's no official AWS conformance suite for DynamoDB. The closest thing the community has is Dynalite's test suite, but over half of its tests are stale against current DynamoDB behaviour (verified March 2026). DynamoDB Local ships with no test suite at all. Every emulator author ends up guessing at behaviour and testing against their own assumptions.
This suite fixes that by running every test against real DynamoDB first, recording what passes, and using those results as the baseline. An emulator only passes if it gives the same answer DynamoDB does.
npm install
# Run against a local target
DYNAMODB_ENDPOINT=http://localhost:8000 npm test
# Quicker run, excludes GSI lifecycle tests (see runtime notes below)
DYNAMODB_ENDPOINT=http://localhost:8000 npm run test:quick
# Run a specific tier
DYNAMODB_ENDPOINT=http://localhost:8000 npm run test:tier1Scored against real DynamoDB's recorded behaviour in each observed region (af-south-1, ap-east-1, ap-east-2, ap-northeast-1, ap-northeast-2, ap-northeast-3, ap-south-1, ap-south-2, ap-southeast-1, ap-southeast-2, ap-southeast-3, ap-southeast-4, ap-southeast-5, ap-southeast-6, ap-southeast-7, ca-central-1, ca-west-1, eu-central-1, eu-central-2, eu-north-1, eu-south-1, eu-south-2, eu-west-1, eu-west-2, eu-west-3, il-central-1, me-central-1, mx-central-1, sa-east-1, us-east-1, us-east-2, us-west-1, us-west-2); a target's Total is its best-matching region, and the Region column names the cohort tied at that rate - all regions, the eu-west-2 baseline plus a count, or a single region it matches that eu-west-2 disagrees with. Behaviour varies by region and over time, so these are point-in-time figures. me-central-1 did not resolve the latest sweep and carries forward the last resolved data. me-south-1 has been dropped from the observed set and is not scored against.
| Target | Tier 1 | Tier 2 | Tier 3 | Total | Region | Pass | Fail | Skip | Version | Date |
|---|---|---|---|---|---|---|---|---|---|---|
| DynamoDB | 100% | 100% | 100% | 100% | all regions | 998 | 0 | 0 | live (AWS) | 2026-07-28 |
| Dynoxide | 100.0% | 100.0% | 100.0% | 100.0% | eu-west-2 + 5 regions | 984 | 0 | 14 | 0.12.0 | 2026-07-28 |
| Dynoxide (wasm) † | 100.0% | 100.0% | 100.0% | 100.0% | eu-west-2 + 5 regions | 785 | 0 | 213 | 0.12.0 | 2026-07-24 |
| ExtendDB | 100.0% | 94.0% | 97.2% | 98.2% | all regions | 895 | 16 | 87 | v0.1.2 | 2026-07-28 |
| Dynalite | 91.4% | 30.0% | 80.9% | 84.6% | 27 regions | 675 | 123 | 200 | 4.0.0 | 2026-07-28 |
| LocalStack | 93.5% | 81.2% | 72.5% | 84.2% | 27 regions | 834 | 156 | 8 | 2026.7.0 | 2026-07-28 |
| Ministack | 92.2% | 71.4% | 79.9% | 84.1% | all regions | 839 | 159 | 0 | 0e9f5965f2fa | 2026-07-28 |
| DynamoDB Local | 92.2% | 82.0% | 72.2% | 83.7% | 27 regions | 818 | 159 | 21 | d89f8fcc6b1a | 2026-07-28 |
| Floci | 91.4% | 61.6% | 70.7% | 78.9% | all regions | 780 | 209 | 9 | d2ecc8035822 | 2026-07-28 |
† Dynoxide (wasm) is a browser/OPFS preview, scored over the operations it implements. Its Skip count is unimplemented surface (PartiQL, transactions, tags, TTL), not passing behaviour, so read its percentage as correctness on what it implements - not a like-for-like comparison with an engine that implements everything.
Live results: the Parity Suite board - the full table for every target, tracked run over run.
DynamoDB is the ground truth, recorded per region. Real DynamoDB disagrees
with itself in a handful of places (the admitted cases are in
registry/splits.json), so each target is scored against every observed
region's recorded behaviour, and its published Total is its best-matching
region. Where several regions tie at that rate, the Region column names the
cohort rather than an arbitrary member: all regions when they all tie,
eu-west-2 + N regions when the historical baseline is among the best, or a
single region when the best cohort is one eu-west-2 disagrees with. A target
fails a behaviour only when no observed region does what it does.
The percentage is correctness over the operations a target implements and
the run could observe - Pass / (Pass + Fail). Two kinds of test are
excluded from it, for different reasons. A skipped test is deliberate: each
test file probes for feature support in beforeAll and skips itself when
the target doesn't implement that operation, so a skip records honest scope,
not a correctness gap. An indeterminate test is a failed observation - a
timeout, an exhausted throttle, a transport fault - and counts neither for
nor against a target, because nobody knows what the answer was. The Skip
column keeps the first visible; a Fail is a behaviour that diverges from
every observed region of real DynamoDB.
This table is regenerated by the Update Results Table workflow —
automatically when a Conformance Tests run finishes on main, and on demand
from the Actions tab. It pulls each target's result artifact, fills the Version
(npm version, container image digest, release tag, or live for real AWS) and
Run date columns from the run, and commits the refreshed table. Run
npm run results:table to preview it locally.
Tier 1 - Core. The operations and behaviours that 90% of DynamoDB users rely on. CRUD, queries, scans, batch operations, GSIs, UpdateTable. If an emulator fails Tier 1, it's not usable.
Tier 2 - Complete. Less common but documented features. Transactions, PartiQL, LSIs, TTL, streams, tags. An emulator that passes Tier 1 but fails some Tier 2 is usable with caveats.
Tier 3 - Strict. Validation ordering, error behaviour at a range of strictness (exact where DynamoDB's wording is stable, structural where its rendering is non-deterministic), edge cases around limits, legacy API compatibility (ScanFilter, QueryFilter). An emulator that passes Tier 1 and Tier 2 but fails some Tier 3 is production-quality for local dev.
The tiers give emulator authors something meaningful to report. "100% Tier 1, 95% Tier 2, 80% Tier 3" tells you far more than a single percentage.
Tier 3 splits into four sub-directories by what each test asserts:
validation-ordering/- which validation fires first when a request has multiple problems. UsestoContainagainst the message; the wording can drift, the ordering should not.error-messages/- the error DynamoDB returns. Uses inlinetry/catchwithexpect(err).toBeInstanceOf(...)andexpect(err.name).toBe(...); the message is matched exactly where it's stable and structurally (toContainon the field and constraint) where AWS's rendering varies by region or SDK version.limits/- hard-coded service limits and the errors that fire when you cross them (item size, batch size, response size, transaction size).legacy-api/- the older request shapes (AttributeUpdates,QueryFilter,ScanFilter,Expected,AttributesToGet) for backwards compatibility.
A new test goes in whichever sub-directory matches what it asserts. If you care about the message the service returns, that's error-messages/. If you only care which error fires, that's validation-ordering/.
Tiers tell you how strict a target is. Tags tell you which capabilities it implements, and they're an independent axis: a test lives in one tier but carries a tag for the operation it covers, a data-plane or control-plane tag, and any cross-cutting trait that applies. That lets you ask a narrower question than the tier score - "how does this target do on just the features I actually use?"
Filter with vitest's --tags-filter:
# Ignore PartiQL
DYNAMODB_ENDPOINT=http://localhost:8000 npx vitest run --tags-filter='!partiql'
# Ignore the legacy request parameters (AttributeUpdates, QueryFilter, ...)
DYNAMODB_ENDPOINT=http://localhost:8000 npx vitest run --tags-filter='!legacy'
# Only item reads and writes, no table management
DYNAMODB_ENDPOINT=http://localhost:8000 npx vitest run --tags-filter='data-plane'
# Drop the operations no emulator implements
DYNAMODB_ENDPOINT=http://localhost:8000 npx vitest run --tags-filter='!cloud-only'
# Compose them, and with tiers: transactions only, excluding cloud-only async
DYNAMODB_ENDPOINT=http://localhost:8000 npx vitest run tests/tier2 --tags-filter='transactions and !cloud-only'The grammar takes and / &&, not / !, or, parentheses, and prefix/* wildcards, and it composes with the tier scripts and directory paths.
The vocabulary lives in one place, src/tags.ts, and stays honest two ways: strictTags rejects an undeclared tag the moment the suite runs, and a coverage guard (npm run test:tooling) fails if any test is left untagged. So an exclusion like !partiql can't silently miss a test that someone forgot to tag.
Operation tags - one per test, matching the operation it exercises.
| Tag | Plane | Operation |
|---|---|---|
put-item |
data-plane | PutItem |
get-item |
data-plane | GetItem |
update-item |
data-plane | UpdateItem |
delete-item |
data-plane | DeleteItem |
query |
data-plane | Query |
scan |
data-plane | Scan |
batch |
data-plane | BatchGetItem, BatchWriteItem |
transactions |
data-plane | TransactWriteItems, TransactGetItems |
partiql |
data-plane | ExecuteStatement, BatchExecuteStatement, ExecuteTransaction |
create-table |
control-plane | CreateTable |
update-table |
control-plane | UpdateTable |
delete-table |
control-plane | DeleteTable |
describe-table |
control-plane | DescribeTable |
list-tables |
control-plane | ListTables |
ttl |
control-plane | UpdateTimeToLive, DescribeTimeToLive |
streams |
control-plane | DynamoDB Streams |
resource-tags |
control-plane | TagResource, UntagResource, ListTagsOfResource |
backups |
control-plane | On-demand backups, point-in-time recovery |
export-import |
control-plane | ExportTableToPointInTime, ImportTable |
kinesis |
control-plane | Kinesis streaming destinations |
contributor-insights |
control-plane | UpdateContributorInsights |
resource-policy |
control-plane | PutResourcePolicy, GetResourcePolicy, DeleteResourcePolicy |
account |
control-plane | DescribeLimits, DescribeEndpoints |
Cross-cutting tags - applied wherever they fit.
| Tag | Meaning |
|---|---|
data-plane |
Reads or writes items |
control-plane |
Manages tables, indexes, or table-level features |
cloud-only |
No emulator implements it; needs real AWS infrastructure, another AWS service, or account/region context |
gsi |
Exercises Global Secondary Indexes |
lsi |
Exercises Local Secondary Indexes |
legacy |
Sends a deprecated request parameter (AttributeUpdates, QueryFilter, ScanFilter, Expected, AttributesToGet), wherever the test lives |
slow |
Long-running against real AWS; the set test:gating excludes |
negative-path |
Asserts only rejections: every case expects a validation error, conditional-check failure, or transaction cancellation |
docker run -d --name ddb-local -p 8000:8000 amazon/dynamodb-local:latest
DYNAMODB_ENDPOINT=http://localhost:8000 npm test
docker stop ddb-local && docker rm ddb-localdynoxide --port 8001 &
DYNAMODB_ENDPOINT=http://localhost:8001 npm test
kill %1A separate engine from the native build above, scored as its own row. The same
query layer compiles to wasm32-unknown-unknown and runs against the official
SQLite-wasm build over OPFS, in a browser Web Worker. Both engines issue the
same SQL, so the two rows differ only where the backends do.
The engine has no HTTP server of its own - it answers a postMessage RPC
(open, execute, capabilities). Reaching it needs a shim that speaks the
DynamoDB HTTP API on a port and forwards each request into a headless browser
running the shipped dist/ bundle. Dynoxide ships that shim as a repo script,
so the suite sees a port like every other target. The script is test-only and
deliberately undistributed - it is not a way to run dynoxide, and getting it
means cloning the repo.
# in a dynoxide checkout: build the bundle, then serve it
npm ci && npm run build:wasm
npm run wasm:serve & # http://127.0.0.1:8003, installs its own browser
# back in this repo
DYNAMODB_ENDPOINT=http://127.0.0.1:8003 CONFORMANCE_TARGET=dynoxide-wasm npm testPort 8003 keeps it clear of the native build on 8001; the script also takes a
second port for its internal static server, defaulting to 8004. --port and
--asset-port override both.
It's a preview with deliberate gaps. PartiQL, TransactWriteItems, tags and TTL
aren't implemented, so those tests skip rather than fail and the row carries a
far higher skip count than any other target. Read the row as "correct on what it
implements", not as a like-for-like comparison with a target that implements
everything.
One scope caveat worth knowing. The shim opens the engine ephemeral, which
forces an in-memory database so no OPFS state can leak between runs. That keeps
the run clean, but it means the conformance path does not exercise OPFS
persistence, which is the wasm build's actual storage layer. Dynoxide covers
persistence in its own browser tests.
npx dynalite --port 8002 &
DYNAMODB_ENDPOINT=http://localhost:8002 npm test
kill %1LocalStack requires a free account. Sign up at localstack.cloud and set your auth token.
export LOCALSTACK_AUTH_TOKEN=your-token-here
docker run -d --name localstack -p 4566:4566 -e LOCALSTACK_AUTH_TOKEN localstack/localstack
DYNAMODB_ENDPOINT=http://localhost:4566 npm test
docker stop localstack && docker rm localstackdocker run -d --name ministack -p 4566:4566 ministackorg/ministack:latest
DYNAMODB_ENDPOINT=http://localhost:4566 npm test
docker stop ministack && docker rm ministackdocker run -d --name floci -p 4566:4566 floci/floci:latest
DYNAMODB_ENDPOINT=http://localhost:4566 npm test
docker stop floci && docker rm flociExtendDB is heavier than the other local targets: it builds from source
(Rust), stores data in PostgreSQL 14+, mandates TLS, and verifies SigV4
against a local IAM store. scripts/run-extenddb.sh automates the whole
bring-up (build, init, a dynamodb:* IAM user, access key, serve) against a
PostgreSQL instance, and the CI job uses it. To wire it up by hand instead,
build ExtendDB, run extenddb init, create an IAM user with a dynamodb:*
policy plus an access key (ExtendDB getting-started guide, "Post-init
workflow"), then start it and point the suite at it:
# ExtendDB 0.1.2 defaults to port 18443, so pin the suite's 8000 explicitly.
# Env vars prefixed EXTENDDB__ layer over the config file (the same mechanism
# scripts/run-extenddb.sh uses), so this makes serve bind 8000.
export EXTENDDB__SERVER__PORT=8000
./target/release/extenddb serve --config extenddb.toml # https://127.0.0.1:8000
# The JS SDK ignores AWS_CA_BUNDLE; trust the self-signed cert via NODE_EXTRA_CA_CERTS.
export NODE_EXTRA_CA_CERTS=~/.extenddb/tls/cert.pem
export AWS_ACCESS_KEY_ID=<access-key-id> # a real key - ExtendDB verifies the signature
export AWS_SECRET_ACCESS_KEY=<secret-access-key>
export AWS_REGION=us-east-1 # SigV4 signing region for the local endpoint; ground truth is recorded per region, so no single region needs matching
export DYNAMODB_ENDPOINT=https://127.0.0.1:8000
CONFORMANCE_TARGET=extenddb npm test # writes results/extenddb.jsonUse 127.0.0.1 or localhost (both are in the cert's SANs). ExtendDB does
not implement PartiQL, so those Tier 2 tests skip.
# Uses the default AWS credential chain (env vars, ~/.aws/credentials, IAM role)
npm test| Target | npm test |
npm run test:quick |
|---|---|---|
| Local emulators | ~2-5 seconds | ~2-5 seconds |
| Real DynamoDB | ~1-3.5 hours | ~20-25 minutes |
The full suite includes 14 UpdateTable GSI lifecycle tests that add and remove Global Secondary Indexes from existing tables. On real DynamoDB, each GSI creation triggers a backfill that usually takes 5-15 minutes even on empty tables, and has been observed taking 25+ on a slow night. These tests are important for conformance but they dominate runtime against real AWS.
test:quick excludes the GSI lifecycle tests for faster local iteration. CI's gating real-DynamoDB job runs test:gating, which drops the GSI lifecycle tests and the S3 and Kinesis integration suites (see "Operations no emulator implements" below), so a slow async import can't redden the build. Emulator targets run the full npm test since GSI creation is instant locally.
Nothing is dropped from real AWS by being off the gate, only moved. Real-AWS coverage runs in three lanes, split by runtime rather than by importance:
| Lane | Scope | Gates the build |
|---|---|---|
test:gating |
the suite minus the two below | yes |
test:integrations |
S3 export/import, Kinesis | no |
test:gsi |
the 14 UpdateTable GSI lifecycle tests | no |
The GSI lane exists because a full green run of that file was measured at 2h50m against real AWS on a slow backfill night, far longer than the gating run can absorb. It gets a lane sized for it instead of being skipped.
Because the published DynamoDB row is scored across the whole suite, the
Ground-truth coverage job unions the three lanes after every scheduled run
and fails if any test in the suite has no real-AWS observation behind it. Run
it yourself with node scripts/ground-truth-coverage.mjs --reference results/<emulator>.json <ground-truth files>. A hole in ground truth is the
one thing here that is never allowed to be quiet.
Ground truth first. Every test is validated against real DynamoDB. Behaviour is recorded per region: a weekly sweep runs the full suite in every commercial region, and the few behaviours where regions genuinely disagree are held, with evidence, in registry/splits.json. If DynamoDB's behaviour changes, the suite updates.
Observable behaviour only. Tests verify what comes back over the wire: response bodies, error types, error messages. No testing of internal implementation details.
SDK-driven. Tests use the AWS SDK v3 for JavaScript rather than raw HTTP. This tests what real applications actually experience.
Endpoint-agnostic. A single environment variable (DYNAMODB_ENDPOINT) points the suite at any target. No target-specific code paths, no special cases.
tests/
tier1/ # ~475 tests
createTable/ # basic, gsi, lsi
putItem/ # basic, conditions, validation, expressions, dataTypes, ...
getItem/ # basic, validation, projection, consumedCapacity
deleteItem/ # basic, validation
updateItem/ # basic, conditions, validation, paths
query/ # basic, gsi, lsi, expressions, select, numericKeys, binaryKeys
scan/ # basic, validation, gsi, lsi, parallel, select, filterOperators
batchWriteItem/ # basic, validation
batchGetItem/ # basic, validation
deleteTable/ # basic
describeTable/ # basic
listTables/ # basic
updateTable/ # basic
tier2/ # ~196 tests
transactions/ # transactWrite, transactGet
partiql/ # executeStatement, batchExecuteStatement, executeTransaction
ttl/ # basic
streams/ # basic
tags/ # basic
updateTable/ # gsi
tier3/ # ~324 tests
validation-ordering/ # per-operation validation error ordering
error-messages/ # exact error message strings
limits/ # itemSize, batchLimits, responseSize, transactionLimits,
# numberPrecision, emptyValues, reservedWords
legacy-api/ # expected, attributeUpdates, queryFilter, scanFilter, attributesToGet
src/client.ts- DynamoDB and Streams client, configured from theDYNAMODB_ENDPOINTenv varsrc/helpers.ts- table lifecycle, assertion helpers (expectDynamoError,cleanupItems,waitForGsiConsistency)src/setup.ts- global beforeAll/afterAll that creates 5 shared tablessrc/types.ts-TestTableDefandKeyDeftypes
paritysuite.org is built from site/, an npm workspace in this repository. It renders the files in results/ as current standings, a page per target with its score over time, and a browsable archive of every recorded run. It imports the suite's own target maps and pass-rate arithmetic, so the board and the table above can't disagree about a target's name, its link, or its score.
npm run site:dev # http://localhost:8080
npm run site:build # writes site/_site/
npm run site:testsite/README.md covers the data flow and the build; AGENTS.md covers the architecture and the invariants.
# Run against a target and save JSON output
DYNAMODB_ENDPOINT=http://localhost:8000 npx vitest run --reporter=json --outputFile=results/dynamodb-local.json
# Generate the comparison table from all saved results
npm run results:tableThis suite uses the AWS SDK v3 (not raw HTTP), which means it can't test:
- Request signing validation - the SDK always signs correctly
- Error wire format -
__typefield naming,messagevsMessagecasing - Content-type handling - the SDK always sends
application/x-amz-json-1.0 - Connection-level behaviour - HTTP headers, chunked encoding, CRC32 checks
You'd need a raw HTTP test layer using fetch() with aws4 signing for those. The dynalite test suite is a good reference for that approach.
- Follow existing patterns in the relevant tier directory
- Use
expectDynamoError()for error assertions, not try/catch - Use
cleanupItems()inafterAllfor data cleanup - Use
ExpressionAttributeNamesfor all attribute names in expressions (avoid reserved words) - Use
ConsistentRead: trueon all read-back assertions - Test against real DynamoDB first - if AWS fails, the test is wrong by definition
- Start the target on a port
- Run:
DYNAMODB_ENDPOINT=http://localhost:<port> npx vitest run --reporter=json --outputFile=results/<target>.json - Generate the table:
npm run results:table - Submit a PR with the results JSON
If the target speaks HTTPS only or verifies request signatures (ExtendDB is
the first such target), two extra steps apply: trust its certificate with
NODE_EXTRA_CA_CERTS=/path/to/cert.pem (the JS SDK does not read
AWS_CA_BUNDLE), and pass a real AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
whose policy allows the operations the suite exercises. Before committing the
results JSON, grep it for your key to be sure no credential leaked into it.
If the engine doesn't speak DynamoDB HTTP at all - a browser or embedded engine
reached over its own RPC - it can still be tracked, provided the vendor fronts
it with a shim exposing the HTTP API on a port (Dynoxide wasm is the first such
target). The suite stays endpoint-agnostic either way. Two things the shim has
to get right. It must start from clean state, because the suite creates its
shared tables in beforeAll and never resets the target. And for any operation
the engine doesn't implement it must return UnknownOperationException, a
message matching unknown operation / not implemented / unsupported operation / is not supported, or HTTP 501. That's what isUnsupportedFault
in src/infra.ts looks for; anything else arrives as an ordinary error and the
operation is scored as a failure instead of a skip.
All test data must be synthetic. Don't use real names, emails, addresses, or any personally identifiable information in test fixtures.
| Operation | Tier 1 | Tier 2 | Tier 3 |
|---|---|---|---|
| PutItem | basic, conditions (incl. parens), validation, expressions, dataTypes, consumedCapacity, itemCollectionMetrics | error messages | |
| GetItem | basic, validation, projection, consumedCapacity | error messages | |
| UpdateItem | basic, conditions (incl. parens, non-existent key branch), validation, paths | error messages | |
| DeleteItem | basic, conditions (incl. parens), validation | error messages | |
| Query | basic, GSI, LSI, expressions (incl. KeyCondition + Filter parens), select, numericKeys, binaryKeys, pagination | error messages, validation ordering | |
| Scan | basic, validation, GSI (incl. pagination), LSI (incl. pagination), parallel, select, filterOperators, filterExpression parens | error messages, validation ordering | |
| BatchWriteItem | basic, validation | error messages | |
| BatchGetItem | basic, validation | error messages | |
| CreateTable | basic, GSI, LSI | error messages, validation ordering | |
| DeleteTable | basic | ||
| DescribeTable | basic | ||
| ListTables | basic | ||
| UpdateTable | basic (throughput, billing mode) | GSI lifecycle | |
| TransactWriteItems | basic, conditions (incl. parens, non-existent key branch), idempotency, cancellation | error messages | |
| TransactGetItems | basic, validation | error messages | |
| ExecuteStatement | INSERT, SELECT, UPDATE, DELETE, parameterised, RETURNING | error messages (RETURNING) | |
| BatchExecuteStatement | batch, partial failure, RETURNING honoured | ||
| ExecuteTransaction | atomic, rollback, RETURNING rejected | error messages (RETURNING) | |
| UpdateTimeToLive | enable, validation | ||
| DescribeTimeToLive | describe | ||
| TagResource | add, list, remove, validation | ||
| DynamoDB Streams | ListStreams, DescribeStream, GetRecords, view types | ||
| Backups | on-demand, continuous (PITR) | ||
| ExportTableToPointInTime / ImportTable | S3 export and import | ||
| Kinesis streaming destination | enable, describe, disable | ||
| UpdateContributorInsights | enable, describe, list | ||
| Resource policies | put, get, delete | ||
| DescribeLimits / DescribeEndpoints | account reads |
A handful of operations only exist on real AWS or reach into another AWS
service, so no emulator implements them and each one skips on every target. The
suite still exercises them against real DynamoDB - characterising AWS's own
behaviour has value - and they all carry the cloud-only tag, so
--tags-filter='!cloud-only' drops the lot:
- Import/Export to S3
- Kinesis Data Streams integration (streaming destinations)
- On-demand backups and Point-in-Time Recovery
- Contributor Insights
- Resource-based policies
- Account reads (DescribeLimits, DescribeEndpoints)
Import/Export and Kinesis lean on slow async control-plane calls that make poor
gate material, so they run in a separate non-gating job via
npm run test:integrations rather than on the gating run. They still run
against real AWS every scheduled run, and the ground-truth coverage check
fails if they don't.
Genuinely not covered, with no tests yet:
- Global Tables
- DynamoDB Accelerator (DAX)
When the suite surfaces a divergence in a target and you want to reference it from that target's own issue tracker, cite the suite as the independent source it is. The reference carries weight precisely because the suite is not the engine's own test harness: it scores every target against the same live-AWS baseline, so "the conformance suite flags this" says more than a self-written test can.
Disclosure. This suite is maintained by the same person who maintains Dynoxide, one of the engines it scores. Dynoxide runs through the same automated matrix as every other target, against the same live-AWS ground truth. The tests and the results are in this repo.
Fill in the bracketed parts. The block is the same whichever engine the finding concerns:
Found by Parity Suite, the DynamoDB conformance suite (paritysuite.org), an independent project that scores multiple engines against live AWS DynamoDB.
Operation: [e.g. CreateTable] Expected (real DynamoDB, [region, e.g. eu-west-2]):
[the exact response or error message real AWS returns]Observed in [target] [version]: [what the target did instead] Suite test: [public link to the specific test, pinned to a commit or tag]
Two details keep the citation honest:
- Link the specific test, and pin it. Use a commit SHA or tag (
.../blob/<sha>/...), never.../blob/main/...: amainlink rots the moment the file is reformatted or the lines shift, while a pinned link points at the exact assertion for good. Link the test itself, not a bare in-repo path, so it resolves for anyone reading the issue. - Pinned test for a specific finding; site row only for a general claim. The pinned test is durable evidence that this exact case diverged. The row on Parity Suite, the DynamoDB conformance suite (paritysuite.org) is a live score that moves with every run, so it answers "how does this engine do overall", not "what broke here". Don't cite a moving score as evidence for a fixed bug.
Real AWS DynamoDB is the ground truth here as everywhere: the "expected" line is what AWS does, captured against a named region, not what any emulator does. If the behaviour is one where regions disagree, say so and name the regions on each side - the admitted cases are in registry/splits.json.
- Contributing and AGENTS.md - how to add tests and targets.
- Code of Conduct - the Contributor Covenant.
- Security policy - how to report a vulnerability or a leaked credential privately.
- Support - where to ask for help.