Skip to content

Store backend support tiers

PyCharter's contract store runs on five backends behind one client interface: PostgreSQL, SQLite, MongoDB, Redis, and in-memory. The client API is identical across all five — every store method works everywhere. What differs is the upgrade story: only the SQL backends have a managed migration path when a PyCharter release reshapes its storage layout.

This page states that difference plainly so you can pick a backend with eyes open.

The tiers

Backend Tier Managed migrations Recommended for
PostgreSQL Production Alembic (pycharter db upgrade, auto-run on API startup) Production deployments
SQLite Production Alembic (same migration chain as Postgres) Single-node production, CI, local work
MongoDB Supported None — manual handling across upgrades Existing Mongo estates that accept manual upgrade steps
Redis Dev / cache None Ephemeral or cache-style usage
In-memory Dev / test n/a (process-lifetime only) Tests, prototyping

What "no managed migrations" means

Alembic migrations live under src/pycharter/db/migrations/versions/ and reshape SQL tables only. When a release changes how contracts are persisted:

  • Postgres / SQLite — run pycharter db upgrade (the REST API also runs it automatically at startup). Done.
  • MongoDB / Redis — there is no automated path. The changelog flags storage-affecting changes; apply them manually, or use the export/re-seed route below.

Document shape changes are a separate, backend-independent mechanism — each persisted artifact carries a format_version header validated at read time on every backend. See Artifact Format Versioning. The gap described here is only about storage layout (collections, key patterns, indexes).

Upgrading a MongoDB or Redis store

The reliable route is a store-to-store copy through the client API — contracts are versioned documents, so reading them out of one backend and writing them into another is a complete, portable round trip:

from pycharter.contract_store import (
    MongoDBContractStore,
    PostgresContractStore,
)

source = MongoDBContractStore("mongodb://localhost:27017/pycharter")
target = PostgresContractStore("postgresql://localhost/pycharter")
source.connect()
target.connect()

for ref in source.list_contracts():
    name, version = ref["name"], ref["version"]
    contract = source.get_contract(name, version)
    target.store_json_schema(name, version, contract["json_schema"])
    if contract.get("coercion_rules"):
        target.store_coercion_rules(name, version, contract["coercion_rules"])
    if contract.get("validation_rules"):
        target.store_validation_rules(name, version, contract["validation_rules"])
    if contract.get("metadata"):
        target.store_metadata(name, version, contract["metadata"])

Run the copy before upgrading (old store → SQL store), or after (SQL store → re-created non-SQL store) — the client API is the same on both sides.

Picking a backend

  • Starting fresh in production? PostgreSQL.
  • Single node, simple ops? SQLite — it shares the Postgres migration chain and upgrades the same way.
  • Already standardised on MongoDB? Supported — budget for manual steps on storage-affecting releases (rare; always changelog-flagged).
  • Redis and in-memory are deliberately positioned for cache/dev/test use, not as systems of record.