Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

pyxpo-sqlite

SQLite databases that persist across app restarts, for pyxpo apps. The API follows expo-sqlite. The phone's Python ships the sqlite3 module, so this package is pure Python: no native code and no rebuild of the native shell.

pip install pyxpo-sqlite
[tool.pyxpo]
modules = ["sqlite"]
import pyxpo_sqlite as SQLite

db = await SQLite.open_database_async("app.db")
await db.exec_async("""
    PRAGMA journal_mode = WAL;
    CREATE TABLE IF NOT EXISTS todo (id INTEGER PRIMARY KEY, title TEXT NOT NULL, done INTEGER DEFAULT 0);
""")
res = await db.run_async("INSERT INTO todo (title) VALUES (?)", "Buy milk")
print(res.last_insert_row_id, res.changes)

row = await db.get_first_async("SELECT * FROM todo WHERE id = ?", res.last_insert_row_id)  # dict or None
rows = await db.get_all_async("SELECT * FROM todo WHERE done = $done", {"$done": 0})         # list of dicts
async for row in db.get_each_async("SELECT * FROM todo"):                                   # one at a time
    ...

async def mark_all():
    await db.run_async("UPDATE todo SET done = 1")
await db.with_transaction_async(mark_all)     # COMMIT, or ROLLBACK if mark_all raises

Functions

Function Notes
open_database_async(name, options=None, directory=None) Opens or creates name in directory (default default_database_directory). ":memory:" opens a private in-memory database. Opening the same file again returns the same connection unless SQLiteOpenOptions(use_new_connection=True).
delete_database_async(name, directory=None) Deletes the file and its -wal, -shm and -journal files. Raises while the database is open.
deserialize_database_async(data) An in-memory database holding data from serialize_async().
default_database_directory <documents>/SQLite: the app's Documents folder on iOS, filesDir on Android.

SQLiteDatabase

Method Notes
exec_async(sql) Runs ;-separated statements without values or results (schema, PRAGMA).
run_async(sql, *values) Returns SQLiteRunResult(last_insert_row_id, changes).
get_first_async(sql, *values) First row as a dict, or None.
get_all_async(sql, *values) All rows as dicts.
get_each_async(sql, *values) Async iterator of rows, read in small batches.
prepare_async(sql) SQLiteStatement: execute_async(*values) returns a result with last_insert_row_id, changes, get_first_async(), get_all_async() and async iteration; also get_column_names_async() and finalize_async().
with_transaction_async(task) Runs await task() inside BEGIN/COMMIT, rolling back if it raises. Queries from other tasks on the same connection meanwhile join the transaction.
with_exclusive_transaction_async(task) Runs await task(txn) on a separate connection inside BEGIN EXCLUSIVE; run queries on txn only. Not for ":memory:".
is_in_transaction_async()
serialize_async(name="main") The database as bytes.
close_async() A shared connection closes when every opener closed it.
database_path, database_name

Values: positional (run_async(sql, 1, "a")), one list or tuple, or one dict for named parameters. Dict keys may keep the prefix used in the SQL ({"$id": 1} for $id, :id, @id) or drop it. Rows map column names to Python values: int, float, str, bytes or None.

Every method also has a _sync form that blocks (for example get_all_sync), and camelCase names work (getAllAsync, runAsync, lastInsertRowId). Async methods run on one worker thread per connection, so the UI stays responsive. SQL errors raise the sqlite3 exceptions (sqlite3.OperationalError, sqlite3.IntegrityError, ...).

Provider and hook

from pyxpo_sqlite import SQLiteProvider, use_sqlite_context

async def migrate(db):
    await db.exec_async("CREATE TABLE IF NOT EXISTS todo (id INTEGER PRIMARY KEY, title TEXT)")

def App():
    return SQLiteProvider(TodoList(), database_name="app.db", on_init=migrate, fallback=Text("Loading..."))

@component
def TodoList():
    db = use_sqlite_context()
    ...

SQLiteProvider props: database_name, options, directory, on_init(db) (awaited before the children render), on_error(error) (without it the error is raised to the nearest ErrorBoundary) and fallback.

Not supported

Change listeners (addDatabaseChangeListener), enableChangeListener, SQLCipher encryption, loading extensions and the key-value Storage export of expo-sqlite (use pyxpo-storage).

Platforms

iOS, Android and desktop. The bundled Python on iOS and Android is 3.13. On desktop, serialize and deserialize need Python 3.11 or later and raise sqlite3.NotSupportedError before that. On desktop, databases live in .pyxpo-data/documents/SQLite under the working directory.

Metadata

Release files for pyxpo-sqlite 0.1.0a1

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

Source distribution (sdist)

Source distribution for pyxpo-sqlite 0.1.0a1
File Size Uploaded
pyxpo_sqlite-0.1.0a1.tar.gz 11.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyxpo-sqlite 0.1.0a1
File Interpreter ABI Platform
pyxpo_sqlite-0.1.0a1-py3-none-any.whl Python 3 none any Details

Total release size: 22.3 kB

Release files / pyxpo_sqlite-0.1.0a1.tar.gz

Download URL pyxpo_sqlite-0.1.0a1.tar.gz
Size 11.4 kB
Tags Source
SHA-256 checksum
How to use checksums
83efa9e71ca1c6bd349db475e9bd9a3cf1197338e484ca657061f4d1b90a08ca
BLAKE2b-256 checksum
How to use checksums
f40ae199314b15538df0a8e5019f9e7d1e91775fccdd26a96e9b45fc7e6d208d
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 16, 2026.

Transparency log

Release files / pyxpo_sqlite-0.1.0a1-py3-none-any.whl

Download URL pyxpo_sqlite-0.1.0a1-py3-none-any.whl
Size 10.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5b4781f952ec55aa56b12bf88f783336c199ade54a90d9089d4c6a4d7e539ad1
BLAKE2b-256 checksum
How to use checksums
834af9a316ba563138f39aebab13af4d19f18811df1233943af712e542611bea
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 16, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0a1 This release

2 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