Skip to main content

swarmlite

tests PyPI license

Verifiable serverless SQLite hosting on Ethereum Swarm.

Publish an ordinary SQLite file to Swarm and run SELECT against it — fetching only the B-tree pages the query plan touches, each one verifiable against the file's 32-byte content address. No database server anywhere.

Measured live (Bee 2.8.1 light node, Gnosis mainnet, 134.5 MB database):

$ swarmlite query "bzz://<root>/demo.db" \
      "SELECT title FROM posts WHERE id = 73123" --stats
Post 73123: on sqlite
fetched 5 pages (20 KB) in 5 reads, of a 134.5 MB file    # 0.02 s

(<root> stands for the 64-hex reference swarmlite publish prints; the CLI will remind you if a placeholder slips through.)

Warm repeats fetch nothing; an FTS5 full-text search fetched 12 pages.

Status: v2. The Python read path (swarmlite.connect, swarmlite query), the publisher (swarmlite publish, with feed support), and the browser reader (js/, SQLite-WASM — no install, no wallet, no extension) are implemented, tested (offline suites + opt-in live round-trips), and demonstrated live, including bzzf:// feed reads and a self-contained demo site. docs/USER_GUIDE.md has the complete setup and worked examples; the lookup tables — every export, signature, flag and URL form, pinned against the code by the test suite — are in docs/REFERENCE.md (the document to hand to an AI agent); design in docs/DESIGN.md, plan in docs/roadmap.md.

How it works

SQLite never touches storage directly — all I/O goes through its VFS interface, and a read-only VFS needs three methods. SQLite's default page (4 KB) equals a Swarm chunk; a query walks a B-tree, so even on a multi-GB file a point lookup touches ~4 pages. swarmlite maps xRead(offset, n) onto swarmfs range reads, with an LRU page cache in front:

application          plain SELECT
SQLite engine        unmodified (apsw)
bzz-VFS shim         xRead(off, n) -> ranged fetch     <- this package
swarmfs              f.seek(off); f.read(n)
Bee                  /bytes, HTTP range reads

Writes stay where SQL writes belong: the publisher works on a local file — full SQL, real transactions — then ships an immutable snapshot and optionally advances a feed. Every publish is a permanent snapshot; the old roots keep working. (Precedent for the read path: phiresky's sql.js-httpvfs over plain HTTP ranges; Swarm adds verification and permanence.)

Quick start

pip install swarmlite            # PyPI: pulls swarmfs automatically

or for development:

git clone https://github.com/petfold/swarmlite
cd swarmlite
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[test]"

pytest                           # 43 tests, no node needed
python examples/offline_demo.py  # the demo, offline — no node, no funds

The offline demo runs the identical code path through an in-memory filesystem: a cold point lookup on a 134 MB database fetches 4 pages.

Going live

With a Bee node (e.g. Swarm Desktop) and a usable postage stamp — see the User Guide for stamp buying and sizing. The demo above ran in RAM, so first materialize a database file to publish (or use your own SQLite file):

python -c "import sys; sys.path.insert(0, 'examples');
from offline_demo import build
open('demo.db', 'wb').write(build(rows=30000))"

swarmlite publish demo.db
# pin:  bzz://<root>/demo.db      <- the 64-hex root hash is minted HERE

That printed root is the database's content address — save it; it is also re-derivable by publishing the identical file again. Then:

swarmlite query "bzz://<root>/demo.db" \
    "SELECT title FROM posts WHERE id = 12345" --stats

No stamp yet? swarmlite publish demo.db --buy prices a batch sized for the file, shows the xBZZ cost, and buys it from the node's wallet.

A published root lives exactly as long as its postage batch, and an expired batch cannot be revived — so renewal is part of publishing:

swarmlite stamps                          # life left, and bucket headroom
swarmlite stamps --check --min-ttl 7d      # exit 1 when one needs renewing (cron)
swarmlite stamps topup <batchID> --for 4w  # extend it (asks before spending)

Migrating a blog? examples/wordpress/ turns a standard WordPress export (Tools → Export) into a searchable blog under one Swarm root — list, search, and every post page are queries against one published file.

If the data will ever change, publish into a feed from the first version — the same single upload advances the signed feed AND yields the pin, and readers get a stable URL from day one:

swarmlite publish demo.db --feed mysite --signer <private key hex>
# pin:  bzz://<root>/demo.db
# feed: bzzf://<owner>/mysite/demo.db

Every publish is a permanent snapshot; swarmlite snapshots "bzzf://<owner>/mysite/demo.db" lists the whole version history, each line a pinned bzz:// URL you can still query.

import swarmlite

con = swarmlite.connect(f"bzz://{root}/demo.db")
rows = list(con.execute("SELECT ... "))
print(con.swarmlite_file.stats())   # pages/bytes fetched vs. file size

URL forms: bzz://<root>/site.db pins an immutable version; bzzf://<owner>/<topic> follows a feed to the latest. file:// and memory:// work too (tests, local use). Connections are strictly read-only — DML raises apsw.ReadOnlyError.

In JavaScript (browser and Node)

The same lazy-page trick runs inside SQLite-WASM. npm install swarmlite gets the reader and a pure-JS publisher, zero runtime dependencies: a static page, the reader, the wasm engine and the database all publish under one immutable Swarm root — a multi-GB dataset behind a static site, no server, nothing to install for readers. Full-stack JS developers never need the Python side:

npx swarmlite publish site.db --feed mysite --signer <key hex>
npx swarmlite query "bzz://<root>/site.db" "SELECT ..." --stats --verify

Feed signatures are byte-identical across the two implementations (asserted against shared fixtures), so JS and Python publishers are fully interchangeable.

python js/demo/publish_site.py --stamp <batchID>
# site: http://localhost:1633/bzz/<root>/index.html

Measured live: a cold point lookup fetched 5 pages (20 KB) of a 41.9 MB database; a whole 4-query session 23 pages (92 KB). Feeds resolve in the browser too (resolveFeed), so the page can always show the latest published snapshot. Against an untrusted gateway, verify: true checks every byte client-side against the 32-byte root (BMT per chunk, signature recovery per feed update) — a tampering gateway is caught on the first bad chunk. User Guide §7 has the details.

What this is not

  • Not a SQL engine over Swarm-native indexes — that is recordstore/POT territory.
  • Not OLTP. Feeds are eventually consistent; pin a root when you need reproducibility.
  • Not a write path through the VFS. The publisher pattern is the write API.

Relatives

  • swarmfs — the fsspec backend this builds on (range reads, transactional writes, feeds). Its API is the test-pinned REFERENCE.md.
  • recordstore — versioned key→record store; the natural system of record that a published site.db is materialized from. Likewise: REFERENCE.md.
  • DuckDB + Parquet over range requests — the analytics flavour of the same trick: cookbook with live measurements. And your Postgres/MySQL can feed all of this — the read-replica cookbook shows how.

License

BSD 3-Clause. Author: Peter Foldiak.

Metadata

Release files for swarmlite 0.3.1

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

Source distribution (sdist)

Source distribution for swarmlite 0.3.1
File Size Uploaded Provenance Actions
swarmlite-0.3.1.tar.gz 578.9 kB With provenance Details for swarmlite-0.3.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for swarmlite 0.3.1
File Interpreter ABI Platform Actions
swarmlite-0.3.1-py3-none-any.whl Python 3 none any Details for swarmlite-0.3.1-py3-none-any.whl

Total release size: 602.2 kB

Release files / swarmlite-0.3.1.tar.gz

Download URL swarmlite-0.3.1.tar.gz
Size 578.9 kB
Tags Source
SHA-256 checksum
How to use checksums
5e2b1c6e8be14dcdb35e6e61eb579f2ca2c0ce0cffd88cd88b78a269edb546ac
BLAKE2b-256 checksum
How to use checksums
80fc79be996dbdf45324bde1372331025a86bb8132b0510dc6d234fc3f498d45
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 Aug 4, 2026.

Transparency log

Release files / swarmlite-0.3.1-py3-none-any.whl

Download URL swarmlite-0.3.1-py3-none-any.whl
Size 23.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e06ea22560a981a4cb109d0276439262c734b31fa02bc78c3e55db390d33985e
BLAKE2b-256 checksum
How to use checksums
3a76e6bd51f1df19b3a441f0a8231f8567eaef36cbb3fec9eb73c3112a84c122
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 Aug 4, 2026.

Transparency log

Security for swarmlite 0.3.1

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for swarmlite-0.3.1.tar.gz

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 Aug 4, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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