SQLAlchemy-JSON
Mutation-tracked JSON column types for SQLAlchemy, including deeply nested changes.
Repository Health
Technical Analysis
SQLAlchemy-JSON provides JSON column types for SQLAlchemy that track in-place mutations so the ORM reliably persists changes. Plain JSON columns in SQLAlchemy only detect reassignment, meaning edits to a nested dict or list can silently fail to be written. This library supplies MutableJson for top-level change tracking and NestedMutableJson for tracking edits at any depth, so mutating a value inside a nested structure marks the column dirty and emits the correct UPDATE.
What You Get
- MutableJson for tracking top-level changes to JSON objects
- NestedMutableJson for tracking edits inside nested dicts and lists at any depth
- Drop-in column types that work with both classic and declarative mappings
- Correct dirty-tracking so no manual flag_modified() calls are needed
- A small, dependency-light addition on top of SQLAlchemy
Common Use Cases
- Storing user preferences or settings as a mutable JSON column
- Persisting nested metadata that is edited in place by application code
- Avoiding subtle bugs where nested JSON edits are never written to the database
Under The Hood
Architecture - The library extends SQLAlchemy’s Mutable extension. Column types (MutableJson, NestedMutableJson) associate loaded JSON values with tracking wrappers; NestedMutableJson recursively wraps nested dicts and lists so any in-place mutation propagates a change event up to the owning attribute, marking it dirty for the next flush.
Tech Stack - Pure Python built directly on SQLAlchemy (>=0.7), with pytest for tests and no other runtime dependencies.
Code Quality - The codebase is small and focused with a dedicated test module (test/test_sqlalchemy_json.py). The single-responsibility scope keeps it easy to audit and reason about.
API Design - Usage is a drop-in replacement for a JSON column type — declare the column with MutableJson or NestedMutableJson and mutation tracking just works, removing manual flag_modified() calls. The API surface is minimal and predictable.