Dynoxide

io.github.nubo-dbPublished by GitHub account nubo-dbv1.5.0Updated Oct 29, 2026

A DynamoDB emulator with an MCP server exposing 35 DynamoDB tools to coding agents.

VerifiedSTDIODesktop onlyDatabasesDeveloper Tools

Overview

AI-generated overview

A local DynamoDB emulator backed by SQLite that gives an assistant 35 tools to create, query, modify and snapshot DynamoDB tables without AWS.

What you can do
  • Inspect the database and tables: database info, table listing, schema details, TTL and tag configuration
  • Create, update and delete tables, including key schemas, GSIs, LSIs, billing mode and deletion protection
  • Read and write items: single and batch get/put/delete, bulk inserts, update expressions, conditional writes
  • Query and scan tables and indexes, with filters, projection, pagination and count-only mode
  • Run PartiQL statements, batches and all-or-nothing transactions, plus atomic multi-item reads and writes
  • Search vector indexes, read DynamoDB Streams records, sweep TTL, and create, list, restore or delete snapshots
When to use it
Useful when developing or testing code that talks to DynamoDB and you want an assistant to set up tables, seed data and run queries locally without AWS credentials or a JVM-based emulator. Also fits CI pipelines and agent-driven debugging of DynamoDB data models.
Requirements
Runs as a local stdio process, typically via npx dynoxide or the published container image; Node.js is needed for the npm route. No AWS account, credentials, API keys or environment variables are required, and all data stays local.
Before you install
Many tools write or delete data, and some are marked destructive: delete_table removes a table and its data, restore_snapshot replaces all current data, and delete_snapshot removes recovery points. A read-only mode blocks write tools if enabled. It is intended for local development and testing, not as a production DynamoDB replacement, and some behaviours differ from AWS, such as no eventually-consistent reads and a single stream shard.

Installation

In SourceWeft

  1. Open Dynoxide in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

Dynoxide

[crates.io] [docs.rs] [CI] [conformance] [license]

A DynamoDB emulator in Rust, backed by SQLite. Runs as an HTTP server or an MCP server for coding agents, embeds into Rust and iOS applications as a library, and compiles to WebAssembly for the browser.

The crates.io badge above shows the crate version, which covers the Rust library alone. Everything you install rather than depend on carries a separate product version: the binary, the npm packages, the container images, the browser engine and the Action. That is the number dynoxide --version prints and the one to quote in a bug report. Why there are two.

Why Dynoxide?

I built Dynoxide because DynamoDB Local is slow, heavy, and can't embed. It needs a JVM, and the typical Docker-based setups adds ~3 seconds of cold-start, ~209 MB of memory at idle, and a ~225MB Docker image (~473 MB on disk) before you've done anything useful. If you're running integration tests, that's Docker starting, the JVM warming up, and your pipeline waiting.

Dynoxide is a native binary. It starts in milliseconds, idles at ~7.2 MB, and ships as a ~3 MB download. Point any DynamoDB SDK at it and your tests just work.

For Rust projects, there's also an embedded mode - direct API calls via Database::memory() with no HTTP layer at all. Each test gets an isolated in-memory database with zero startup cost. And because it compiles to a native library with no runtime dependencies, it runs on platforms where DynamoDB Local can't, including iOS.

Performance

Local Development (Apple Silicon)
MetricDynoxide (embedded)Dynoxide (HTTP)DynamoDB Local
Cold startup~0.2ms~15ms~2,287ms
GetItem (p50)9µs0.1ms0.8ms
PutItem throughput~51,613 ops/s~6,703 ops/s~945 ops/s
50-test suite (sequential)~484ms~569ms~2,407ms
50-test suite (4x parallel)~203ms~235ms~1,189ms
CI (GitHub Actions)

Numbers from ubuntu-latest (4-core AMD EPYC 7763, 16GB RAM). Commit 17be96a.

MetricDynoxide (embedded)Dynoxide (HTTP)DynamoDB LocalLocalStack (all services)FlociMiniStack
Cold startup<1ms~2ms~2,605ms~12,217ms~228ms~2,636ms
GetItem (p50)16µs0.3ms0.8ms---
50-test CI suite828ms859ms2,628ms---
Full workload (10K items)-3.2s12.2s---
Binary / image (download)~3 MB~3 MB225 MB1.1 GB--
Binary / image (on disk)8 MB8 MB473 MB1.1 GB234 MB162 MB
Idle memory (RSS)~7.2 MB~8 MB~209 MB~387 MB~23 MB~47 MB

The gap is wider on Apple Silicon because the faster CPU amplifies the difference between native code and JVM overhead. Both are real measurements of the same benchmark suite. Full methodology and per-operation breakdowns →

Conformance

Dynoxide is continuously verified against real DynamoDB by Parity Suite, the DynamoDB conformance suite that runs one test matrix against AWS itself and every major DynamoDB emulator. Pass rates move as the suite grows and each engine changes, so rather than pin a snapshot that goes stale, see the live standings:

Disclosure: Dynoxide and Parity Suite are maintained by the same person. The suite scores Dynoxide on the same public matrix it runs against every other engine, and the results and test code are open.

This covers the native build. The WebAssembly build is scored as its own row: it passes every test it implements, with a far higher skip count than any other target because several operations are still missing.

How It Compares

DynoxideDynamoDB LocalLocalStack (all services)FlociMiniStackdynalite
LanguageRustJavaPython + JavaJava (GraalVM native image)PythonNode.js
StorageSQLiteSQLiteSQLite (via DDB Local)Its own (in-memory, persistent or WAL)Its own (in-memory, optional on-disk state)LevelDB
Runtime dependency-JVMDocker + a LocalStack account (auth token)DockerDocker or PythonNode.js
Embeddable (Rust / iOS)✓-----
MCP server for agents✓-----

LocalStack uses DynamoDB Local internally as its DynamoDB engine, so its startup and memory overhead includes DynamoDB Local's JVM plus LocalStack's own Python routing layer. Since March 2026 its image needs a LocalStack account and LOCALSTACK_AUTH_TOKEN to start, even for the services that used to be free. Floci and MiniStack are general AWS emulators like LocalStack, each with its own DynamoDB engine rather than DynamoDB Local.

Quick Start

Run a local server without installing anything:

sh
npx dynoxide --port 8000

Or install it into a project to pin the version, after which npx dynoxide uses that copy:

sh
npm install --save-dev dynoxide

Or run it in Docker, a drop-in for amazon/dynamodb-local:

sh
docker run --rm -p 8000:8000 ghcr.io/nubo-db/dynoxide

Point any AWS SDK or DynamoDB client at http://localhost:8000. For Homebrew, Cargo, pre-built binaries, and embedding as a Rust library, see the installation guide.

Add --log quiet to suppress informational startup and shutdown messages on stderr (useful in test suites). It works on serve, mcp and import --serve or --mcp, and warnings and errors still print. Without --log, the output is unchanged.

Documentation

  • Installation - npm, Homebrew, Cargo, binaries, GitHub Actions, and Docker
  • HTTP server - running the DynamoDB-compatible HTTP API
  • Testcontainers - driving the container from a test suite, and the wait strategy it needs
  • MCP server - the Model Context Protocol server for coding agents
  • DynamoDB Streams - enabling and reading stream records
  • Import CLI - loading data, table filtering, and anonymisation
  • WebAssembly - the browser build and embed contract
  • Using as a Rust library - embedded mode and feature flags
  • Compatibility - operation, expression, and PartiQL coverage versus DynamoDB
  • Versioning - what the version number promises and what forces a major
  • Releasing - release cadence and process

Supported Operations

Dynoxide implements the DynamoDB API across tables, items, query and scan, batches, transactions, PartiQL, streams, TTL, and tags, with GSI and LSI support, the full expression syntax, and DynamoDB-compatible pagination, validation, and error codes. For the operation-by-operation breakdown and a comparison, see the compatibility summary.

Limitations

Dynoxide is built for local development, testing, and CI, not as a production DynamoDB replacement, so two classes of thing are missing on purpose.

Cloud-only operations with no local equivalent aren't implemented: backups and point-in-time restore, global tables, Kinesis streaming, resource policies, and capacity management. Call one and you get an UnknownOperationException.

A few behavioural differences are also worth knowing when you test against it:

  • ConsistentRead is accepted but changes nothing. SQLite is strongly consistent, so every read already is - you can't reproduce eventually-consistent reads.
  • Streams expose a single shard. DescribeStream returns one shard, and its ExclusiveStartShardId and Limit paging parameters are accepted but ignored.
  • Transaction-contention errors (TransactionConflictException, TransactionInProgressException) aren't emulated - there's no concurrent contention in a single process.

For the per-feature support matrix, see the live capability matrix; the full operation-by-operation breakdown is in the compatibility summary.

Acknowledgements

Dynoxide's DynamoDB API semantics and validation logic were informed by dynalite, the excellent DynamoDB emulator built on LevelDB by Michael Hart and now maintained by the Architect team.

Dynoxide is a clean-room Rust implementation. No code was ported directly, but dynalite's thorough approach to matching live DynamoDB behaviour, including edge cases and error messages, was an invaluable reference.

Dynoxide uses SQLite as its storage layer. (AWS's DynamoDB Local also uses SQLite internally.)

License

Dual-licensed under MIT and Apache 2.0. See LICENSE-MIT and LICENSE-APACHE.

Trademarks

Amazon DynamoDB, DynamoDB, and AWS are trademarks of Amazon.com, Inc. or its affiliates. Dynoxide is an independent project and is not affiliated with, endorsed by, or sponsored by Amazon, and nothing here grants any right to use those names or marks.

Source: README.md at commit aecc7ab

Tools

35

batch_execute_partiql

[WRITE] Execute a batch of PartiQL statements. Each statement can be SELECT, INSERT, UPDATE, or DELETE. A member's RETURNING clause is honoured, with the returned item surfaced on that response's Item field. Write statements are blocked in read-only mode.

Parametersstatementsrequiredreturn_consumed_capacity

batch_get_item

Retrieve up to 100 items from one or more tables in a single call. Accepts both PascalCase (Keys) and snake_case (keys) in request_items.

Parametersrequest_itemsrequiredreturn_consumed_capacity

batch_write_item

[WRITE] Write up to 25 put or delete operations across one or more tables in a single call. Accepts both PascalCase (PutRequest/DeleteRequest) and snake_case (put_request/delete_request) keys. Duplicate keys across operations are rejected. ReturnItemCollectionMetrics: SIZE returns partition collection size for tables with LSIs.

Parametersrequest_itemsrequiredreturn_consumed_capacity

bulk_put_items

[WRITE] Bulk-insert items into a table. Faster than repeated put_item calls. Maximum 10,000 items per call. Existing items with the same key are overwritten.

Parametersitemsrequiredtable_namerequiredrecord_streams

create_snapshot

[WRITE] Create a snapshot of the current database state. Returns the snapshot name for later restoration via restore_snapshot. A global limit of 20 snapshots is enforced, and when it is reached auto-snapshots are evicted first, then the oldest manual ones. This holds the database lock for the duration of the copy, so a large database may briefly block other operations.

Parametersname

create_table

[WRITE] Create a new DynamoDB table with specified key schema and optional GSIs and LSIs. Supports BillingMode, ProvisionedThroughput, OnDemandThroughput, SSESpecification, TableClass, Tags, and DeletionProtectionEnabled. The table is available immediately after creation.

Parameterstagskey_schemarequiredtable_namerequiredtable_classbilling_modevector_indexessse_specificationon_demand_throughputstream_specificationattribute_definitionsrequiredprovisioned_throughputlocal_secondary_indexes+2 more

delete_item

[WRITE] Delete a single item by its primary key. Returns the deleted item if return_values is set to ALL_OLD. Blocked if DeletionProtectionEnabled is set on the table. Condition expression values are validated for empty strings/sets/numbers.

Parameterskeyrequiredtable_namerequiredreturn_valuescondition_expressionreturn_consumed_capacityexpression_attribute_namesexpression_attribute_valuesreturn_values_on_condition_check_failure

delete_snapshot

[DESTRUCTIVE] Delete a snapshot by name. Use list_snapshots to see available snapshots.

Parametersnamerequired

delete_table

[DESTRUCTIVE] Delete a table and all its data. An auto-snapshot is created before deletion for recovery via restore_snapshot.

Parameterstable_namerequired

describe_stream

Get details about a DynamoDB Stream including its shards.

Parameterslimitstream_arnrequired

describe_table

Get detailed schema information for a table including key schema, GSIs, LSIs, item count, size, stream config, and TTL settings. Returns an agent-friendly flattened format by default; set raw=true for the full DynamoDB-format response.

Parametersrawtable_namerequired

describe_time_to_live

Get the TTL configuration for a table.

Parameterstable_namerequired

execute_partiql

Execute a PartiQL statement. Supports SELECT (with LIMIT, nested paths), INSERT (with IF NOT EXISTS, parameter placeholders), UPDATE (with SET arithmetic, REMOVE, nested paths), DELETE. UPDATE and DELETE accept a RETURNING clause, surfaced in the response Items: DELETE allows only RETURNING ALL OLD * (returning the deleted item; other variants are rejected), UPDATE allows all four RETURNING <ALL|MODIFIED> <OLD|NEW> * variants. WHERE supports BETWEEN, IN, CONTAINS, IS MISSING, IS NOT MISSING, AND, OR, NOT, parenthesised grouping up to 64 levels deep, and nested paths; AND binds tighter than OR, and a NOT over a group is applied by De Morgan. An index is named in the FROM clause as "table"."index", which serves the read from that GSI or LSI on SELECT only; a write statement rejects the qualifier. An UPDATE or DELETE whose WHERE condition fails is a ConditionalCheckFailedException; with return_values_on_condition_check_failure set to ALL_OLD the error carries the item the condition was evaluated against. Write statements are blocked in read-only mode.

Parameterslimitstatementrequirednext_tokenparametersconsistent_readreturn_consumed_capacityreturn_values_on_condition_check_failure

execute_transaction_partiql

[WRITE] [DESTRUCTIVE] Execute PartiQL statements transactionally (all-or-nothing). Max 100 statements. If any fails, the entire transaction is rolled back. A RETURNING clause is not supported inside a transaction and is rejected with a ValidationException. Example transact_statements: [{"Statement": "INSERT INTO Users VALUE {'pk': 'u1', 'name': 'Alice'}"}]

Parameterstransact_statementsrequiredclient_request_tokenreturn_consumed_capacity

get_database_info

Get database-level information: storage mode, path, size, table count, and per-table summaries. When the data was loaded by dynoxide import, also returns the import's notices and whether any exposures were accepted. Use this as your first call to orient yourself.

Takes no parameters.

get_item

Retrieve a single item by its primary key.

Parameterskeyrequiredtable_namerequiredconsistent_readprojection_expressionreturn_consumed_capacityexpression_attribute_names

get_records

Read stream records using a shard iterator.

Parameterslimitshard_iteratorrequired

get_shard_iterator

Get a shard iterator for reading stream records. Use TRIM_HORIZON for all records or LATEST for new records only.

Parametersshard_idrequiredstream_arnrequiredsequence_numbershard_iterator_typerequired

list_snapshots

List available database snapshots with name, size, and creation time. Returns newest first, up to 20 entries.

Takes no parameters.

list_streams

List DynamoDB Streams, optionally filtered by table name.

Parameterslimittable_name

list_tables

List all DynamoDB tables in the database. Returns table names as an array.

Takes no parameters.

list_tags_of_resource

List tags for a DynamoDB table.

Parametersresource_arnrequired

put_item

[WRITE] Insert or replace an item in a table. Supports conditional writes via condition_expression. Empty strings, empty sets, and invalid numbers are rejected. Sets are deduplicated. Unused ExpressionAttributeNames/Values are rejected.

Parametersitemrequiredtable_namerequiredreturn_valuescondition_expressionreturn_consumed_capacityexpression_attribute_namesexpression_attribute_valuesreturn_values_on_condition_check_failure

query

Query items using a key condition expression. Supports filtering, projection, pagination, and GSI/LSI queries via IndexName. Use select=COUNT to get only Count and ScannedCount without items.

Parameterslimitselectindex_nametable_namerequiredfilter_expressionscan_index_forwardexclusive_start_keyprojection_expressionkey_condition_expressionrequiredreturn_consumed_capacityexpression_attribute_namesexpression_attribute_values

restore_snapshot

[DESTRUCTIVE] Restore the database from a snapshot. This replaces all current data with the snapshot contents. Use list_snapshots to see available snapshot names.

Parametersnamerequired

scan

Scan an entire table or GSI/LSI, optionally applying a filter expression. Use query instead when you know the partition key. Use select=COUNT to get only Count and ScannedCount without items. Use Segment and TotalSegments for parallel scan; segment filtering uses FNV-1a hash at the SQLite level.

Parameterslimitselectsegmentindex_nametable_namerequiredtotal_segmentsfilter_expressionexclusive_start_keyprojection_expressionreturn_consumed_capacityexpression_attribute_namesexpression_attribute_values

search_vectors

[READ] Search a vector index for the nearest entries to a query vector. Exact brute-force KNN over the whole index, so the top-k is the true top-k. COSINE and EUCLIDEAN score as distances, where a self match is 0; DOT_PRODUCT scores as a similarity and can be negative. The vector attribute is excluded from results unless a projection_expression names it and the index projects it. Create the index with create_table's vector_indexes, which is searchable at once. An index added later through update_table refuses with 'Cannot search backfilling vector index' until it settles, for longer than describe_table reports it CREATING, so retry the search rather than waiting for the status.

Parameterstop_krequiredindex_namerequiredtable_namerequiredsearch_vectorrequiredprojection_expressionreturn_consumed_capacityexpression_attribute_namesexpression_attribute_valuessearch_condition_expression

sweep_ttl

[WRITE] Run a TTL sweep, deleting expired items from all TTL-enabled tables. Returns the number of items deleted.

Takes no parameters.

tag_resource

[WRITE] Add tags to a DynamoDB table.

Parameterstagsrequiredresource_arnrequired

transact_get_items

Execute up to 100 get operations atomically. Returns a consistent snapshot of all requested items.

Parameterstransact_itemsrequiredreturn_consumed_capacity

transact_write_items

[WRITE] Execute up to 100 write actions (Put, Update, Delete, ConditionCheck) atomically. All succeed or all fail. Response includes ItemCollectionMetrics for tables with LSIs.

Parameterstransact_itemsrequiredclient_request_tokenreturn_consumed_capacity

untag_resource

[WRITE] Remove tags from a DynamoDB table.

Parameterstag_keysrequiredresource_arnrequired

update_item

[WRITE] Update an item's attributes using an update expression. Supports SET, REMOVE, ADD, DELETE actions and conditional updates. REMOVE/ADD/DELETE on key attributes are rejected. Arithmetic uses arbitrary-precision decimal.

Parameterskeyrequiredtable_namerequiredreturn_valuesupdate_expressioncondition_expressionreturn_consumed_capacityexpression_attribute_namesexpression_attribute_valuesreturn_values_on_condition_check_failure

update_table

[WRITE] Update a table: add/remove GSIs, change stream settings, switch BillingMode, ProvisionedThroughput or OnDemandThroughput, change TableClass, or toggle DeletionProtectionEnabled.

Parameterstable_namerequiredtable_classbilling_modeon_demand_throughputstream_specificationvector_index_updatesattribute_definitionsprovisioned_throughputdeletion_protection_enabledglobal_secondary_index_updates

update_time_to_live

[WRITE] Enable or disable Time to Live (TTL) on a table. Specify the attribute that holds the expiration timestamp.

Parameterstable_namerequiredtime_to_live_specificationrequired

Version history

5
  1. v1.5.0LatestOct 23, 2026
  2. v1.4.0Oct 21, 2026
  3. v1.3.0Oct 10, 2026
  4. v1.2.1Sep 20, 2026
  5. v1.2.0Sep 16, 2026

Score

90% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 days25 pts
  • Auth declared10 pts

    Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.

  • Tools listedRequired15 pts
  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts