dbwarden is a layered tool: the CLI parses arguments and global flags, the commands layer orchestrates workflows (migrate, rollback, make-migrations, status, check, and the rest), and the engine below it handles the actual work: model discovery, snapshot extraction, diffing, versioning, checksums, and safety classification. Repositories persist migration and lock metadata, and the database layer executes SQL through backend-aware connections.
The metadata layer is kept deliberately database-agnostic. schema/ holds dialect-agnostic constructs (TableMeta, IndexSpec, the runtime metadata container attached to each model), while databases/ holds the concrete backend specs for ClickHouse, MySQL, PostgreSQL, MariaDB, and SQLite. The import rule is one-way: schema/ never imports backends at module load (backend metas are resolved lazily, inside functions), so the metadata layer stays portable and each backend plugs into the same pipeline.
Each backend exposes a small handler contract: extract, model_spec_from_tables, canonicalize, diff, and emit. A registry driver runs that contract in order for every object type: extract the snapshot state, derive the model state, canonicalize both sides, diff into typed operations, and emit backend SQL. That is why one workflow covers PostgreSQL tables, ClickHouse engines, and MySQL row formats alike.
CLI (Typer)
-> Commands layer
-> Engine layer (planning, parsing,
version, checksum, model discovery)
-> Repository layer (migration
+ lock records)
-> Database layer (SQLAlchemy
connection + SQL execution)extract(snapshot) raw backend state
model_spec_from_tables() model state
canonicalize(spec) normalized form
diff(a, b) typed operations
emit(op) backend SQL