dynamoxy
A typed, async DynamoDB ORM for Python, with a Rust core. Declare models with type hints (or pydantic) and get validated, atomic DynamoDB access, plus an in-memory DynamoDB for your tests.
import asyncio
from datetime import datetime
import dynamoxy
from dynamoxy import Attr, field, partition_key
class User(dynamoxy.Model, table="users"):
user_id: Attr[str] = partition_key()
email: Attr[str] = field(unique=True)
name: Attr[str] = field(min_length=1)
visits: Attr[int] = field(default=0)
created_at: Attr[datetime] = dynamoxy.created_at()
version: Attr[int] = dynamoxy.version()
by_email = dynamoxy.GlobalIndex(partition_key=email)
async def main() -> None:
async with dynamoxy.Client(region="eu-west-1") as client: # or dynamoxy.testing.memory_client()
await client.ensure_tables(User)
users = client.repository(User)
ada = await users.create(User(user_id="u1", email="ada@example.com", name="Ada"))
await ada.increment(User.visits) # atomic; `ada` is refreshed in place
ada.name = "Ada Lovelace"
await ada.save() # only if nobody changed it meanwhile (version)
try:
await users.create(User(user_id="u2", email="ada@example.com", name="Imposter"))
except dynamoxy.UniqueConstraintError as error:
print(f"{error.field} is taken")
found = await users.query(index=User.by_email, email="ada@example.com").first()
print(found)
asyncio.run(main())
Highlights
-
Typed end to end. Fields are values on instances and typed paths on the class (
User.visits > 3). Your type checker catchesUser(visits="3")andUser.visits > "3". -
Errors that tell you what to fix. DynamoDB's rules are checked before a request is sent:
ValidationError: the transaction has 120 operations (guard items of unique attributes included); DynamoDB allows 100
A refused write raises
ItemAlreadyExistsError,VersionConflictErrororUniqueConstraintError, not a bareConditionalCheckFailedException. -
Writes that mean what they say.
create()never overwrites,save()checks the version,update()is atomic without a read. -
Unique values, timestamps and versions are maintained for you.
-
Retries built in, with backoff and jitter. Nothing fails silently.
-
An in-memory DynamoDB for tests. No Docker, no AWS account. It refuses what DynamoDB refuses, simulates faults and answers in microseconds:
dynamoxy.testing.inject_fault(client, operation="GetItem", error="throttling", times=2) with dynamoxy.collect() as usage: user = await users.get("u1") # throttled twice, retried assert usage.retries == 2
-
Observable. Structured logs and event hooks out of the box; OpenTelemetry spans and metrics when you configure it. Item contents are never logged.
-
Single-table design with key templates such as
"CUSTOMER#{customer_id}". -
Fast. 2.5 to 5 times less client CPU per call than boto3 (numbers).
-
No required dependencies. pydantic and OpenTelemetry are optional extras.
Also covered: indexes, cursors, batches, transactions, TTL, streams, backups, PartiQL and table management.
Already using pydantic?
Inherit from dynamoxy.PydanticModel instead of BaseModel and mark the key. Pydantic keeps
validating, and the class stays a pydantic model, so the same Customer can be a FastAPI request or
response model and a DynamoDB table (uv add 'dynamoxy[pydantic]'):
from typing import Annotated
from pydantic import BaseModel, Field
import dynamoxy
class Address(BaseModel): # plain pydantic models nest as maps
street: str
city: str
class Customer(dynamoxy.PydanticModel, table="customers"): # instead of BaseModel
customer_id: Annotated[str, dynamoxy.PartitionKey()]
email: Annotated[str, dynamoxy.Unique()]
name: str = Field(min_length=1)
address: Address | None = None
await client.ensure_tables(Customer)
customers = client.repository(Customer)
await customers.create(Customer(customer_id="c1", email="ada@example.com", name="Ada"))
customer = await customers.get("c1") # a validated Customer
A model you would rather not touch can stay as it is: subclass it together with
dynamoxy.PydanticModel and re-declare only the fields that need a marker, such as the key (see
the pydantic guide).
Install
uv add dynamoxy # or: pip install dynamoxy
uv add 'dynamoxy[pydantic]' # pydantic models
uv add 'dynamoxy[otel]' # OpenTelemetry
Documentation
| Getting started | First model, connecting, first queries |
| Usage guide | The compact reference (dynamoxy guide) |
| Guides | Modeling, reading, writing, transactions, single-table design, testing, ... |
| Examples | Runnable programs |
| Reference | Configuration, errors, events |
| Architecture | How it works, invariants, decisions |
| Changelog | Release notes |
AI agents: run dynamoxy guide (or read AGENT_GUIDE.md)
before writing code with dynamoxy; application repositories can copy the skill in
skills/dynamoxy. Agents changing dynamoxy itself start with
AGENTS.md.
How it works
A Rust core speaks DynamoDB: the AWS SDK for transport, plus dynamoxy's own retries, batching, events and the in-memory backend. Python owns what you touch: models, validation, repositories and hooks. A few choices worth knowing:
- Values never go into expression strings, so reserved words and injection are non-issues.
- Unique values are guard items written in the same transaction, since indexes are only eventually consistent.
- Models hold no client, so one model works with several accounts, regions or test stores.
- Stored formats are API: they stay readable across versions.
The architecture and the decision records have the details.
Performance
Round trips cost every client the same. What a library adds is CPU time per call, spent holding the GIL. dynamoxy does the protocol work in Rust.
Client CPU time per call against a local emulator (dynamoxy returns validated models; the others return DynamoDB JSON):
| dynamoxy | boto3 | aiobotocore | |
|---|---|---|---|
GetItem, one item |
0.14 ms | 0.66 ms | 0.60 ms |
PutItem, one item |
0.19 ms | 0.67 ms | 0.61 ms |
Query, 100 items |
0.65 ms | 1.68 ms | 1.71 ms |
- Cold start (import and first read): 51 ms, against 115 ms for boto3.
- In memory, a
get()takes about 13 µs, so large test suites run in seconds.
Why it is fast: signing, HTTP, JSON and retries run in Rust outside the GIL; each model plans its encoding once, when the class is created; and features you do not use cost nothing.
Measured with dynamoxy 0.2.0 on Python 3.14, aarch64 Linux, October 2026. Your hardware will
differ:
scripts/benchmark.py
measures it on yours.
Contributing
See CONTRIBUTING.md. The project is young (0.x): breaking changes are possible in minor versions and are called out in the changelog.
License
Metadata
Release files for dynamoxy 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| dynamoxy-0.3.0.tar.gz | 323.5 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| dynamoxy-0.3.0-cp312-abi3-win_arm64.whl | CPython 3.12 | abi3 | Windows ARM64 | Details |
| dynamoxy-0.3.0-cp312-abi3-win_amd64.whl | CPython 3.12 | abi3 | Windows x86-64 | Details |
| dynamoxy-0.3.0-cp312-abi3-musllinux_1_2_x86_64.whl | CPython 3.12 | abi3 | Linux musl 1.2+ x86-64 | Details |
| dynamoxy-0.3.0-cp312-abi3-musllinux_1_2_aarch64.whl | CPython 3.12 | abi3 | Linux musl 1.2+ ARM64 | Details |
| dynamoxy-0.3.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.12 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| dynamoxy-0.3.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.12 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| dynamoxy-0.3.0-cp312-abi3-macosx_11_0_x86_64.whl | CPython 3.12 | abi3 | macOS 11.0+ x86-64 | Details |
| dynamoxy-0.3.0-cp312-abi3-macosx_11_0_arm64.whl | CPython 3.12 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 52.5 MB
Release files / dynamoxy-0.3.0.tar.gz
| Download URL | dynamoxy-0.3.0.tar.gz |
|---|---|
| Size | 323.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
50aafabeca922f3e84cb929686968469fef9ab45e7e8ff993d83972a42accd40
|
|
BLAKE2b-256 checksum How to use checksums |
c322372afdd823d1d0b813fb8dc4b280ed95d80541c01324b49fddc645923246
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency logRelease files / dynamoxy-0.3.0-cp312-abi3-win_arm64.whl
| Download URL | dynamoxy-0.3.0-cp312-abi3-win_arm64.whl |
|---|---|
| Size | 6.5 MB |
| Tags | CPython 3.12 Windows ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
764eee3a5034f06666138f4318f10257995446964d9e241bc3101339a250a5ae
|
|
BLAKE2b-256 checksum How to use checksums |
9b6c16f9a5af9017194555050f019d78dd9009f9cb8b11612cf412f7b9b1ea7d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency logRelease files / dynamoxy-0.3.0-cp312-abi3-win_amd64.whl
| Download URL | dynamoxy-0.3.0-cp312-abi3-win_amd64.whl |
|---|---|
| Size | 6.8 MB |
| Tags | CPython 3.12 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
32dc2a025e401108d2a1069b4524e27c49395cf6aff227b661be77ccc14a2cd0
|
|
BLAKE2b-256 checksum How to use checksums |
949673931a4a87273672c3ab7e71a270c32a723ca2c1107fea85362cc49a8396
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency logRelease files / dynamoxy-0.3.0-cp312-abi3-musllinux_1_2_x86_64.whl
| Download URL | dynamoxy-0.3.0-cp312-abi3-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 6.7 MB |
| Tags | CPython 3.12 Linux musl 1.2+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
6cfaed89764d173cf782aa220df399ed093c374825b51168b9772fe6dadeefc2
|
|
BLAKE2b-256 checksum How to use checksums |
e0d261d6757f4d03ed41f03aa685231d170698d6662b9a07e617adbf523bf092
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency logRelease files / dynamoxy-0.3.0-cp312-abi3-musllinux_1_2_aarch64.whl
| Download URL | dynamoxy-0.3.0-cp312-abi3-musllinux_1_2_aarch64.whl |
|---|---|
| Size | 6.3 MB |
| Tags | CPython 3.12 Linux musl 1.2+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
f3d96933cf329ba318e1c7a820112f0614b727f93b4d4e0bf96c2c923a6f2d12
|
|
BLAKE2b-256 checksum How to use checksums |
0bd147eeb23a8b46bea13eb89ed7b8770678508eab34cecfd216bb3c87c206a3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency logRelease files / dynamoxy-0.3.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | dynamoxy-0.3.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 6.7 MB |
| Tags | CPython 3.12 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
441dd31de8bc0c20a44f9174d0e3f42c4ec49a5ca56d27b2213f7e92e33cca82
|
|
BLAKE2b-256 checksum How to use checksums |
378d8e8a17599626b8faa4f78328e06e69983939bd3050cac81e359470420d40
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency logRelease files / dynamoxy-0.3.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | dynamoxy-0.3.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 6.3 MB |
| Tags | CPython 3.12 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
a2d0c55e16d54717356f99687b476299fcd913d91e4a471c1031a88920cda843
|
|
BLAKE2b-256 checksum How to use checksums |
df8be7ac3dce6d5f509797d7a608c1e805514be4b69e9ed86840116aa6f035ef
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency logRelease files / dynamoxy-0.3.0-cp312-abi3-macosx_11_0_x86_64.whl
| Download URL | dynamoxy-0.3.0-cp312-abi3-macosx_11_0_x86_64.whl |
|---|---|
| Size | 6.6 MB |
| Tags | CPython 3.12 abi3 macOS 11.0+ x86-64 |
|
SHA-256 checksum How to use checksums |
ab1ad2850eab10da119ecd082592020e77ecd1d3877501666652cf97d3b80cde
|
|
BLAKE2b-256 checksum How to use checksums |
aca33a4a0cd7d838e39fdf406be19704c274ca3d63ebe5910d47eb4f73f10bfd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency logRelease files / dynamoxy-0.3.0-cp312-abi3-macosx_11_0_arm64.whl
| Download URL | dynamoxy-0.3.0-cp312-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 6.1 MB |
| Tags | CPython 3.12 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
a8a9b3a8573a7364491f37199f22aa4b4432a21e9c6dcbf33ceab112a6a5d8cf
|
|
BLAKE2b-256 checksum How to use checksums |
4d821913105fa96b52b299783f2bb702d48e0e7b0cfeb0558511173d305d7229
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency log