Skip to main content

CedroDB for Python

Keep application documents, events and recovery history in one local database. CedroDB is an embedded document engine written in Rust, with a native Python API. A form submission and its outbox event can commit together, indexed queries find pending work, and a durable changefeed lets your application resume processing after restarting. Version 0.3 adds integrity verification and portable backups.

Use it for offline forms and inspections, desktop application state, local automation, or small services that need JSON documents without running a database server. The Python package calls the Rust engine directly; it does not spawn a process or maintain a second Python storage implementation.

Experimental software. Active documents and indexes live in RAM, a directory has one owning handle/process, and the log currently has no compaction. See the limits below before choosing it for important data. There are no performance claims or production-readiness guarantees.

Installation

For the 0.3.0 release on PyPI:

python -m pip install cedrodb==0.3.0

PyPI publication requires the project's publisher configuration. If that version is not available there yet, obtain its wheel or self-contained source archive from GitHub Releases, then install the downloaded file:

python -m pip install ./cedrodb-0.3.0.tar.gz

A compatible wheel needs no Rust toolchain at runtime. Source installation requires Python 3.9+, Rust 1.85+ and a working C linker. The source archive bundles the Rust core; it builds independently of the repository.

The release wheel build matrix covers four platform/architecture combinations:

Platform Architecture Python ABI
Linux x86_64 CPython 3.9+ (cp39-abi3)
macOS Apple Silicon / ARM64 CPython 3.9+ (cp39-abi3)
macOS Intel / x86_64 CPython 3.9+ (cp39-abi3)
Windows x86_64 CPython 3.9+ (cp39-abi3)

Check a release's assets for its available builds and platform tags. Other architectures may require a source build; a Linux wheel does not imply support for every Linux distribution or musl-based system.

Quickstart: save and query documents

from cedrodb import Database

with Database("./app.cedro") as db:
    orders = db.collection("orders")
    orders.put_many({
        "order:1": {"status": "paid", "total": 120},
        "order:2": {"status": "pending", "total": 35},
    })
    orders.create_index("status")
    page = orders.find_page(
        [{"field": "status", "op": "eq", "value": "paid"}], limit=20
    )
    print(page["records"])       # [{"key": "order:1", "value": {...}}]
    print(page["used_index"])    # status
    print(orders.get("order:1"))
    print(db.stats())

Collections store any supported JSON value, including arrays and null. put replaces the complete value for a key; delete removes it. put_many accepts a mapping or an iterable of (key, value) pairs and commits them atomically.

find() returns one list of {key, value} records. find_page() also returns next_after, scanned and used_index. To continue, pass next_after as after; None means there is no continuation. iter_records(page_size=100) iterates bounded result pages. Results are ordered by key; pages do not share a snapshot. Writes between requests can change subsequent results. Limits are 1..1000 records.

Filters are combined with AND. Operations are eq, ne, gt, gte, lt, lte, and exists (with a boolean value). A field is a top-level name or an RFC 6901 JSON Pointer, such as /customer/city. Missing fields differ from JSON null; use exists to test absence. Equality indexes stay consistent with writes and must be recreated after reopening or restoring a database.

Offline writes and the atomic outbox

Commit the document and the event in the same transaction. Your uploader can then find the event after a restart without losing the corresponding form.

from cedrodb import Database

with Database("./field-app.cedro") as db:
    with db.transaction() as tx:
        tx.put("forms", "inspection:1", {
            "site": "Santo Domingo", "status": "pending_upload"
        })
        tx.put("outbox", "inspection:1:submitted", {
            "event_id": "inspection:1:submitted",
            "type": "inspection.submitted", "form_id": "inspection:1"
        })

    page = db.changes(since=0, limit=100)
    for transaction in page["transactions"]:
        for operation in transaction["operations"]:
            if operation["collection"] == "outbox" and operation["kind"] == "put":
                print(operation["value"])
    # Save page["next_cursor"] only after processing succeeds.

The feed survives close/reopen and contains complete put/delete operations in transaction order. since is an exclusive transaction cursor, starting at zero, and belongs to this database history. limit counts transactions (1..1000), not operations. has_more tells you whether another page is available. Pages also cap encoded frame bytes at max_frame_bytes + 12 without splitting a transaction; decoded Python objects require additional memory.

Your application owns the uploader, checkpoint storage and event deduplication. A crash after an external effect but before its checkpoint can repeat delivery; CedroDB does not promise exactly-once delivery or provide a background worker.

db.transaction() buffers writes and copies staged values. A successful context exit commits one batch; an exception rolls it back. Reads continue to observe committed data, without read-your-writes, snapshot isolation or automatic conflict detection. Alternatively, pass operations directly to db.batch([...]):

with Database("./app.cedro") as db:
    db.batch([
        {"kind": "put", "collection": "orders", "key": "order:3", "value": {"total": 10}},
        {"kind": "delete", "collection": "drafts", "key": "order:3"},
    ])

Verify, back up and restore

A backup contains the committed log inside a versioned container with a length and CRC checksum. It preserves transaction history and changefeed cursors.

from pathlib import Path
from cedrodb import Database

backup = Path("./field-app.backup")      # Must not already exist.
restored = Path("./recovered.cedro")      # Must not already exist, even empty.

with Database("./field-app.cedro") as db:
    print(db.verify())
    print(db.backup(backup))

report = Database.restore_backup(backup, restored)
print(report)  # log_bytes, transactions, records, content_bytes

with Database(restored) as db:
    db.collection("forms").create_index("status")
    print(db.changes(since=0))

verify() reads and validates the committed log; it does not repair data. backup(path) creates a new file and never overwrites an existing file or folder. restore_backup(backup_path, destination_path) validates the complete container and log before creating a new destination directory. Parent directories must already exist. Static restore returns an IntegrityReport dictionary, without retaining an open handle or file lock. Index definitions are handle-local and must be recreated; the committed documents and history are retained.

For custom content limits, pass the same configuration to restore and open:

limits = {"max_document_bytes": 2_097_152, "max_state_bytes": 134_217_728}
Database.restore_backup("./large.backup", "./large-restored.cedro", **limits)
with Database("./large-restored.cedro", **limits) as db:
    print(db.verify())

All three methods are synchronous and perform disk I/O; the native operation releases Python's GIL. Verification replays state in memory and can require another copy of the live state plus a frame buffer. CRC detects accidental corruption; it does not authenticate or encrypt a backup. Interrupted I/O can require inspecting and removing an incomplete output before retrying. See backup format and recovery details.

Run the complete offline-form example with python examples/offline_forms.py.

Conditional updates and null

from cedrodb import Database, DELETE, MISSING

with Database("./app.cedro") as db:
    claims = db.collection("claims")
    created = claims.compare_exchange(
        "job:1", expected=MISSING, replacement={"owner": "worker-1"}
    )
    removed = claims.compare_exchange(
        "job:1", expected={"owner": "worker-1"}, replacement=DELETE
    )
    missing = claims.get("unknown", MISSING) is MISSING

replacement is required. None stores JSON null; DELETE removes the record. MISSING as expected means the key must not exist, while expected=None requires a stored null. A mismatch returns False without appending a transaction. The comparison covers the complete JSON value. Exact integers and integral floats compare equally only within the safe range ±2**53; booleans remain distinct.

API reference

Object Methods
Database collection, batch, transaction, changes, stats, verify, backup, close
Database.restore_backup Static restore with optional content-limit keywords
Collection put, get, delete, put_many, find, find_page, iter_records, create_index, compare_exchange, aggregate
Transaction put(collection, key, value), delete(collection, key), commit, rollback, context manager

Database(path, *, max_document_bytes=1_048_576, max_frame_bytes=16_777_216, max_state_bytes=67_108_864) opens or creates a directory. Paths accept strings and os.PathLike objects returning strings. Use a context manager or close(); closing is idempotent and releases the native lock immediately. db.closed reports its state. Existing collection handles fail with DatabaseClosedError after close.

Engine failures raise CedroError. Unsupported JSON raises TypeError or ValueError; integers outside [-2**63, 2**64 - 1] raise OverflowError. NaN, infinity, cycles, non-string object keys and unsupported objects are rejected before mutation. Supported integers round-trip exactly. JSON depth is limited to 64 levels, and the transport always uses allow_nan=False. Type annotations and a py.typed marker are included.

Current limits

  • One open owning handle/process per directory; its native calls are serialized.
  • Documents, equality indexes and transaction offsets are held in RAM. Encoded content limits exclude allocator overhead, indexes and temporary buffers.
  • Append-only log with no compaction, retention or bounded total disk use.
  • Handle-local indexes and key-based query pagination, without snapshot isolation.
  • aggregate(field) uses floating-point arithmetic on a top-level numeric field and can lose integer precision above 2**53; stored documents remain exact.
  • No SQL, MVCC, replication, encryption or automatic synchronization.

Upgrade from 0.2 to 0.3

Existing document, batch, query, CAS and changefeed APIs keep their signatures. The database log format is unchanged; 0.2 stores can be opened directly. Version 0.3 adds db.verify(), db.backup(path) and Database.restore_backup(...). Backup containers are distinct from raw cedro.log files: use backup() to create them. Restore requires a new destination and preserves the original history/cursor sequence. Recreate equality indexes after opening the restored store, and configure matching limits when your store exceeds the defaults.

Build and test

python -m venv .venv
# Activate the environment with your platform's activation command.
python -m pip install 'maturin>=1.15,<2'
python scripts/prepare_core.py
maturin build --release --out dist
maturin sdist --out dist
python -m pip install ./dist/<your-platform-wheel>.whl
python -m unittest discover -s tests -v
python scripts/verify_sdist.py dist/cedrodb-0.3.0.tar.gz
python examples/offline_forms.py

prepare_core.py copies only the core manifest, license and Rust source into ignored core/. Regenerate that copy after engine changes. The sdist includes those files and has no dependency on ../.. at installation. verify_sdist.py rebuilds an extracted archive, installs the resulting wheel in an isolated target and runs its tests. Keep Cargo.lock for reproducible dependency versions.

Source · Demo · Issues

Metadata

Release files for cedrodb 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cedrodb 0.3.0
File Size Uploaded
cedrodb-0.3.0.tar.gz 37.5 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for cedrodb 0.3.0
File
cedrodb-0.3.0-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
cedrodb-0.3.0-cp39-abi3-manylinux_2_34_x86_64.whl CPython 3.9 abi3 Linux glibc 2.34+ x86-64 Details
cedrodb-0.3.0-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details
cedrodb-0.3.0-cp39-abi3-macosx_10_12_x86_64.whl CPython 3.9 abi3 macOS 10.12+ x86-64 Details

Total release size: 1.9 MB

Release files / cedrodb-0.3.0.tar.gz

Download URL cedrodb-0.3.0.tar.gz
Size 37.5 kB
Tags Source
SHA-256 checksum
How to use checksums
4644f28b2c2f3ab7942ad75edef339b98b29bab3617c1dfd796333df56486eb4
BLAKE2b-256 checksum
How to use checksums
1c31006dc603ec1234bace7757721a8baf3b266dc2a6fa9e7c4fb9b68de12063
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 15, 2026.

Transparency log

Release files / cedrodb-0.3.0-cp39-abi3-win_amd64.whl

Download URL cedrodb-0.3.0-cp39-abi3-win_amd64.whl
Size 411.9 kB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
8976e2d0b67b7e6037f4468ab92dff79a2ffc458227c83b8f29609c3439c6868
BLAKE2b-256 checksum
How to use checksums
d79ef427b943be4bdd82d9cc79994501dddf3a14b8fc1c9323bf4e7a62dee83e
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 15, 2026.

Transparency log

Release files / cedrodb-0.3.0-cp39-abi3-manylinux_2_34_x86_64.whl

Download URL cedrodb-0.3.0-cp39-abi3-manylinux_2_34_x86_64.whl
Size 491.5 kB
Tags CPython 3.9 Linux glibc 2.34+ x86-64 abi3
SHA-256 checksum
How to use checksums
fd5094e13f8b986bc3714f7166d7196fbd951b2aaf82185309afdab98c46b7eb
BLAKE2b-256 checksum
How to use checksums
4f93fbcc125a5e0d4d4e0d676736dd9d0316007c3869c5dbbac9bbbd17d0af6b
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 15, 2026.

Transparency log

Release files / cedrodb-0.3.0-cp39-abi3-macosx_11_0_arm64.whl

Download URL cedrodb-0.3.0-cp39-abi3-macosx_11_0_arm64.whl
Size 443.4 kB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
c24b6be08bdfe6d913a4c8494a9e66a9633edae7e721bbb9792b78a934e02032
BLAKE2b-256 checksum
How to use checksums
758970c0b37f756f6b2222b066fe2283234d463fb728a52200bf7ab692f3b814
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 15, 2026.

Transparency log

Release files / cedrodb-0.3.0-cp39-abi3-macosx_10_12_x86_64.whl

Download URL cedrodb-0.3.0-cp39-abi3-macosx_10_12_x86_64.whl
Size 470.5 kB
Tags CPython 3.9 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
157e90690ec0c361a3dcb69f70f68f1d5a6e8cfb982fbc25469ee5482c7bef92
BLAKE2b-256 checksum
How to use checksums
b68a81ec48272f63b9c8459c94fba779a7a81da23e1f49087086d781b48fb5cb
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 15, 2026.

Transparency log

Release history Release notifications | RSS feed

0.9.0

7 release files

0.8.0

5 release files

0.7.0

5 release files

0.6.0

5 release files

0.5.0

5 release files

0.4.0

5 release files

This release

0.3.0 This release

5 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page