v1.2.1 Open source. Built in Rust.

Local DynamoDB.
Without the baggage.

A DynamoDB emulator backed by SQLite. Use your existing SDK locally, then take the same engine into CI, your app, or the browser.

No Docker. No JVM. Just localhost.

brew install nubo-db/tap/dynoxide

macOS, Linux & Windows All install options ↗

YOUR EXISTING AWS SDK
Python · JS · Go · Java · PHP · RustDynoxidelocalhost:8000
localhost / dynoxide EXAMPLE
$ dynoxide
Dynoxide listening on http://127.0.0.1:8000
Ready in ~2 ms Measured on CI runners
app.tsSame SDK. One new endpoint.
const client = new DynamoDBClient({
  region: "us-east-1",
  endpoint: "http://localhost:8000",
  credentials: {
    accessKeyId: "local",
    secretAccessKey: "local"
  }
});
DynamoDB APIPowered by Rust + SQLite
A Verified against real AWS
1,251 tests. 0.2% divergence.
New in v1.2.1 rmcp moves to 2.2.0, clearing GHSA-9pj6-vhgr-3mwh, GHSA-33f5-2c5q-wgwj and GHSA-9g45-5xwm-f3wc against the 1.x line. Changelog

Dynoxide in numbers

~2ms
Cold start

Ready before your SDK has finished connecting. Measured on GitHub Actions runners.

35tools
Ready for your coding agent

Create tables, query data, and manage snapshots through the built-in MCP server.

3MB
One static binary

No Docker, no JVM, no database to install. About 8 MB of RAM at idle.

A
Parity Suite grade

First of 9 emulators, with 0.2% divergence from real DynamoDB.

One engine

Five ways to run it

The same emulator, whether you need a local server, a service in a pipeline, an in-process library, a browser build, or an MCP server for your coding agent.

Local HTTP server

A native binary that serves the DynamoDB wire protocol on a port. A drop-in for DynamoDB Local: point any AWS SDK at the endpoint.

npx dynoxide

CI service

A GitHub Action (or the Docker image) that brings Dynoxide up in a pipeline. A ~3 MB download with no JVM warmup, so the database stops being the slow part of the job.

nubo-db/dynoxide/action@v1.2.1

Embedded library

A Rust crate that runs the engine in-process, with no server and no network. Single-digit microsecond operations, and it runs on platforms DynamoDB Local can't, including iOS.

cargo add dynoxide-rs

MCP server

A built-in Model Context Protocol server, over stdio or HTTP. A coding agent can create tables, query data, and manage snapshots without leaving the conversation.

dynoxide mcp

Browser (WebAssembly)

Run the emulator in the tab via WebAssembly, persisted to OPFS. Drops onto ordinary static hosting, with no special server headers.

npm install @dynoxide/wasm-engine

Dual-licensed under MIT or Apache-2.0, so you can embed it in your own application and redistribute it.

Startup

Ready before the SDK has connected

Time from process start to accepting requests, on one scale. The figures come from the benchmark pipeline behind the README's CI table, run on GitHub Actions hardware.

PROCESS START → FIRST REQUESTms / lower is better
Dynoxide ~2 ms
DynamoDB Local ~2,833 ms · 1,400× slower
LocalStack ~11,848 ms · 5,900× slower

Local development on Apple Silicon is faster still.

Lowest divergence of 9 emulators

Tested against the real thing

1,251 tests against real DynamoDB on AWS. The same requests, the same expected answers, for every emulator. See how closely each one matches, and how much it supports.

See the live results on Parity Suite

Coverage runs across, divergence runs down from zero, so real DynamoDB defines the top right corner and every emulator sits at its distance from it. The sloping lines are Parity Suite's grade boundaries, and they slope because a test a target declines counts a third as heavily against the letter as one it gets wrong.
Parity Suite conformance results, ordered by divergence
Grade Target Divergence Coverage
A Dynoxide 0.2% 98.9%
B ExtendDB capped by coverage 1.8% 78.7%
B extenddb sqlite capped by coverage 2.1% 82.8%
B Ministack 7.1% 95.8%
B LocalStack 8.1% 95.3%
C Dynalite capped by coverage 11.5% 69.1%
C Floci 15.0% 95.3%
C DynamoDB Local 15.7% 94.2%
F kumo 45.2% 78.3%

A skip and a fail are not the same problem. An operation an emulator declines is something you find in minutes and plan around; one it gets quietly wrong is something you find in production. Divergence sets the letter and coverage can only lower it. The suite also only tests what it tests, so a behaviour with no test is a blind spot rather than a pass. How the grading works. Suite: paritysuite/dynamodb-conformance.

WebAssembly

DynamoDB in a browser tab

The same emulator, compiled to WebAssembly and published on npm. No server, no install: just DynamoDB running on the page, on the official SQLite wasm build. It persists to OPFS, so a table you create survives a reload. Nothing leaves the page.

It runs in a Web Worker and needs no special server headers, no cross-origin isolation, no COOP/COEP, so the whole thing, around 990 KB gzipped, drops onto ordinary static hosting.

Create-table, put, get, delete, query, scan and PartiQL all work, over base tables and both secondary index types. So does SearchVectors over a vector index, running the same exact-KNN search as the native build. It covers a subset of that build (streams, TTL, tags and write transactions aren't wired yet) and it reports the exact set it supports at boot.

The console below is accesspatterns.dev, embedded on this page and running on this same wasm build. It holds a product catalogue with a vector index and a GSI over one table: SearchVectors answers "something like this, in stock", and a Query on the GSI answers "everything in a price band". Run it live fetches the engine into your tab and answers from there, with the cost of every operation beside the response.

In the pipeline

Built for CI, not just your laptop

A fast emulator doesn't just save you time locally, it changes what's practical in your pipeline. When startup takes milliseconds instead of seconds, you can spin up a fresh database per test. No shared state. No cleanup. No flaky tests.

Pair that with dynoxide import and you're running integration tests against real data shapes: anonymised, compressed, loaded in seconds from a snapshot of production.

A 3 MB download with no dependencies means no Docker layer caching, no JVM warmup eating into your build minutes, and no "works on my machine" divergence between local and CI.

Already built around amazon/dynamodb-local in a container? Swap the image. The official ghcr.io/nubo-db/dynoxide is a 5 MB drop-in with the same API, where you'd otherwise pull 225 MB. You don't need Docker, but if you want it, it's no longer the slow part.

dynoxide in CI
Installcurl + tar·~1s
Load snapshotdynoxide import·~3s
Run 50 testsisolated instances·~0.8s
Total~5s
DynamoDB Local in CI
Pull Docker image225 MB (473 MB on disk)·~30s
JVM cold startwait for ready·~4s
Run 50 testsshared instance·~3s
Total~37s

Import

Test against production data shapes, safely

The bugs you cannot reproduce locally usually come from the shape of real data. dynoxide import reads a DynamoDB Export and anonymises it as it loads, so you can work against production shapes without holding production data.

Rules fake, mask, hash, redact or null an attribute. Fields you mark as consistent get the same replacement everywhere they appear, so the joins still work when you query it.

Single-table designs are the hard case, because the email is usually inside the partition key as well as beside it, and a rule on the attribute never reaches the key. Hand it your OneTable schema and the keys get rebuilt from the anonymised values, prefixes and all.

If an original value reaches the output, the run exits 3, lists every case it found, and refuses to start a server on the result. Read the import guide

rules.toml
[[rules]]
match  = "attribute_exists(email)"
path   = "email"
[rules.action]
type     = "hash"
salt_env = "ANON_SALT"

[consistency]
fields = ["userId", "email"]
what you get back
Attributes rewrittenby rule
Keys rebuilt--data-model
Joins checkedfails on a break
Original value left inexit 3

npm

Drop-in replacement for dynalite

If you're using dynalite for local DynamoDB during development, switching is one line. You don't need to know or care that it's Rust under the hood.

Before
$ npx dynalite

No transactions or streams

After
$ npx dynoxide

Transactions, streams, and a ~2 ms start

The npm package ships platform-specific binaries, the same approach used by esbuild, Biome and Turbo. A thin wrapper pulls in the right binary for your OS at install time. No compilation, no native dependencies, no surprises.

Your existing dev setup stays the same. Same SDK calls, same endpoint, same table definitions. The only difference is the name in your package.json, and the fact that your local DynamoDB starts in milliseconds instead of seconds.

npm install --save-dev dynoxide

dynoxide on npm

FAQ

Frequently asked questions

How fast does Dynoxide start?

Dynoxide starts in ~2ms on GitHub Actions CI runners (HTTP mode). That's over 1,400x faster than DynamoDB Local (~2,833ms) and nearly 6,000x faster than LocalStack (~11,848ms). Numbers come from the benchmark pipeline that writes the CI table in the README, run on GitHub Actions hardware.

Does Dynoxide require Docker?

No. Dynoxide is a single native binary - no Docker, no JVM, no dependencies. Just download and run. The entire binary is ~3 MB.

Is Dynoxide compatible with DynamoDB?

Parity Suite, a DynamoDB conformance suite maintained by Dynoxide's author, runs hundreds of behavioural tests against real DynamoDB on AWS, then against every emulator the same way. Every engine is scored identically against live AWS, and the results and test code are public, so you can compare Dynoxide against every other local emulator yourself.

Can I use Dynoxide as a local DynamoDB emulator?

Yes. Dynoxide is a drop-in replacement for DynamoDB Local. It works with any AWS SDK - just point your endpoint to localhost:8000.

How does Dynoxide compare to DynamoDB Local?

Dynoxide starts around 1,400x faster (~2ms vs ~2,833ms), is a ~3 MB download rather than a 225 MB Docker image, and needs no Docker or JVM. Both are measured by the same conformance suite, so you can compare how closely each matches real DynamoDB.

Can I develop against production data without leaking it?

Yes, that's what `dynoxide import --rules` is for. Rules fake, mask, hash, redact or null attributes on the way in, so production values never land on your laptop. On a single-table design pass `--data-model` with your OneTable schema and the importer rebuilds pk, sk and index keys from the anonymised attributes, so a key built from an email doesn't keep the real one. If any original value still reaches the output the run exits 3 and refuses to start a server on it.

Why does the CLI say 1.2.0 when crates.io says 2.0.0?

They're separate version streams. The product version covers everything you install - the CLI, npm, Docker, Homebrew, the GitHub Action and the browser engine. The dynoxide-rs crate on crates.io carries its own number, because a breaking change to the Rust API shouldn't force a major version on everyone who never touches it. Quote the product version in a bug report. See /docs/versioning.

Try it in ten seconds

One install, one command, and any DynamoDB SDK pointed at localhost.

brew install nubo-db/tap/dynoxide