framework‑agnostic database schema evolution tool for Python
schemactl is a next‑generation database migration tool built on top of SQLAlchemy metadata and Alembic autogeneration.
Unlike traditional migration tools, schemactl is designed as a schema evolution engine, not just a migration runner. It is architecture‑first, deterministic, and ready to integrate with LLMs, agents, and autonomous workflows.
Most migration tools are:
- framework‑coupled
- imperative and manual
- hard to reason about at scale
- unfriendly to AI‑assisted workflows
schemactl takes a different approach:
- Framework‑agnostic – works with pure SQLAlchemy
- Metadata‑driven – schema is the single source of truth
- Diff‑based – migrations are generated from real schema changes
- Deterministic – reproducible and auditable
- AI‑ready – designed for LLM review, risk analysis, and human‑in‑the‑loop control
Your SQLAlchemy models (metadata) define the desired state of the database. For example, in app/models.py:
from sqlalchemy import Column, Integer, String, DateTime, Boolean
from sqlalchemy.orm import declarative_base
from datetime import datetime
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
email = Column(String(255), unique=True, nullable=False)
username = Column(String(100), unique=True, nullable=False)
created_at = Column(DateTime, default=datetime.utcnow)
is_active = Column(Boolean, default=True)schemactl compares this metadata against the actual database schema and generates migrations automatically.
Instead of thinking in terms of "apply SQL files", schemactl models:
- schema diffs
- schema versions
- schema state
This enables future features like:
- automated rollback planning
- migration safety scoring
- AI‑assisted reviews
- policy enforcement
pip install schemactlschemactl --helpPlanned commands:
schemactl new # generate a new migration from metadata diff
schemactl up # create DB (if needed) and apply pending migrations
schemactl create # create the database
schemactl drop # drop the database
schemactl migrate # run pending migrations
schemactl rollback # rollback the last migration
schemactl down # alias for rollback
schemactl status # show migration status
#schemactl dump # dump schema.sql
#schemactl load # load schema.sql
schemactl wait # wait for DB readiness
To generate an empty migration file:
schemactl new --message add_users_tableTo auto-generate a migration based on model changes, use the --auto flag and specify the path to your models:
schemactl new \
--message create_initial_tables \
--auto \
--models app.modelsThe command generates a new migration file:
migrations/
└── 20251215_create_initial_tables.sql
The content of the generated file will look like this:
-- migrate:up
-- Auto-generated migration: create_initial_tables
CREATE TABLE users (
id SERIAL NOT NULL,
email VARCHAR(255) NOT NULL,
username VARCHAR(100) NOT NULL,
created_at TIMESTAMP WITHOUT TIME ZONE,
is_active BOOLEAN,
PRIMARY KEY (id),
UNIQUE (email),
UNIQUE (username)
);
-- migrate:down
-- Rollback: create_initial_tables
DROP TABLE users;schemactl upWhat happens:
- Creates the database if it does not exist
- Ensures the
schema_migrationstable exists - Applies all pending migrations in order
- Records applied revisions deterministically
.
├── schemactl/ # Main package source
│ ├── cli.py # CLI commands
│ ├── services/ # Business logic and services
│ │ └── migration.py
│ │ └── model_loader.py
│ ├── adapters/ # Database and Alembic adapters
│ │ ├── alembic.py
│ │ └── database.py
├── migrations/ # Generated migration files
├── tests/ # Unit and integration tests
├── pyproject.toml # Project configuration (Poetry)
└── poetry.lock # Poetry lock file
This structure follows Clean Architecture and keeps infrastructure concerns isolated.
- Architecture first, code second
- Prefer declarative over imperative
- Explicit state tracking
- Simple core, extensible edges
APIs may change. Migration format is not yet stable.
MIT
Contributions are welcome, especially in:
- migration safety
- rollback logic
- Async / cloud databases
Design discussions > code dumps.