Schema-safe database workflow with validated replay, bootstrap, data, and codegen
Project description
matey
matey is a database migration system for teams that want more than “run some SQL files”.
Install:
pip install matey
It keeps schema artifacts in git, validates migration replay in scratch databases, bootstraps empty databases to head, manages live data as explicit artifacts, and can generate SQLAlchemy models from the validated schema.
Supported engines
Current engine set:
sqlitepostgresmysqlclickhousebigquerybigquery-emulator
Notes:
bigquery-emulatoris supported, but it has narrower semantics than real BigQuery.
Feature matrix
| Feature | matey | dbmate | Flyway | Liquibase | Alembic |
|---|---|---|---|---|---|
| SQL-file migrations | Yes | Yes | Yes | Yes | Partial |
| Repo-native multi-target workspace | Yes | No | No | No | No |
| Validated replay in scratch DBs | Yes | No | No | No | No |
Canonical committed schema.sql |
Yes | Yes | No | No | No |
| Verified intermediate schema states | Yes | No | No | No | No |
| Fast bootstrap without replay | Yes | No | Partial | Partial | No |
| Live data artifact workflow | Yes | No | No | Partial | No |
| SQLAlchemy codegen from validated schema | Yes | No | No | No | Yes |
| BigQuery support | Yes | Yes | Yes | Yes | No |
| BigQuery emulator support | Yes | Partial | No | No | No |
| ClickHouse support | Yes | Yes | Partial | Partial | No |
| Migration autogeneration | No | No | No | No | Partial |
How matey works
Matey has two levels of configuration:
- a workspace config at the repo root
- a target config inside each database target directory
A target is just a path in your repo. There are no logical target names to map back to directories.
A typical workflow looks like this:
- write a migration under
migrations/ - run
matey schema apply - matey replays the migration chain into a scratch database
- if replay succeeds, matey writes schema artifacts (
schema.sql,schema.lock.toml, checkpoints) - if codegen is enabled, matey also writes
models.py - later,
matey db ...commands compare live database state against the current worktree target state
That scratch replay step is the main difference from a plain migration runner.
Scratch replay
matey schema plan and matey schema apply do not just trust the migration files. They:
- create or lease a scratch database
- load the best available starting point (zero, checkpoint, or bootstrap state)
- replay the current migration chain into that scratch database
- dump and compare the resulting schema
- write artifacts only after replay succeeds
This is why matey can detect problems like:
- broken migration ordering
- incompatible checkpoint/schema artifacts
- drift between committed artifacts and actual replay behavior
- backend-specific issues that only show up when SQL is really executed
Useful flags:
--test-urlpoints scratch at an explicit test database base--cleanforces replay from empty--keep-scratchleaves the scratch DB behind for debugging
Workspace and target layout
Workspace config
The workspace config lives at the repo root in either:
matey.toml- or
pyproject.tomlunder[tool.matey]
It is just an explicit list of target paths:
targets = [
".",
"db/core",
"services/analytics/db",
]
Target layout
Each target directory contains its own database artifacts and config.
<target>/
config.toml
schema.sql
schema.lock.toml
migrations/
checkpoints/
data/
data.toml
*.jsonl
models.py
Target-local config lives in config.toml.
engine = "postgres"
url_env = "CORE_DATABASE_URL"
test_url_env = "CORE_TEST_DATABASE_URL"
[codegen]
enabled = true
generator = "tables"
# options = "..."
Quickstart
1. Install matey
pip install matey
2. Initialize the current directory as a target
matey init \
--engine postgres \
--url-env DATABASE_URL \
--test-url-env TEST_DATABASE_URL
That will:
- create or update the workspace
matey.toml - add the current directory as a target (
".") - write
config.toml - initialize:
schema.sqlschema.lock.tomlmigrations/checkpoints/data/
To also scaffold CI in the resolved workspace root:
matey init \
--engine postgres \
--url-env DATABASE_URL \
--test-url-env TEST_DATABASE_URL \
--ci github
3. Create a migration
matey db new "create users"
4. Validate replay and write schema artifacts
matey schema apply
5. Apply migrations to a live database
matey db up
Everyday workflows
Start a new target
Use this when you are setting up a database target for the first time.
matey init \
--path db/core \
--engine postgres \
--url-env CORE_DATABASE_URL \
--test-url-env CORE_TEST_DATABASE_URL \
--ci github
matey db new --path db/core "create users"
matey schema apply --path db/core
Result:
- the target directory is initialized
- the workspace target list is updated
- optional CI is written at the workspace root when
--ciis provided - a migration file exists
- schema artifacts are regenerated from validated replay
models.pyis generated if codegen is enabled
Move schema forward safely
Use this when you have added or edited migrations and want to update both repo artifacts and a live database.
matey schema apply --path db/core
matey db up --path db/core
Result:
schema applyreplays the migration chain in scratch and refreshes artifactsdb upapplies pending migrations to the live database
Inspect before changing anything
Use this when you want to understand what matey thinks will happen.
matey lint --all
matey schema plan --path db/core
matey db plan --path db/core
Use --sql or --diff when you want the replayed schema text or a diff instead of a summary.
Bootstrap a new database to head
Use this when you need to bring up an empty database quickly without replaying the entire migration chain live.
matey db bootstrap --path db/core
Result:
- matey loads the committed head schema into the empty database
- verifies
dbmate status - verifies the resulting live schema against the current worktree head
Roll back and verify
Use this when you want to step backward and still keep matey’s safety checks.
matey db down --path db/core --steps [N]
Result:
- matey rolls back the requested migrations
- verifies the resulting live schema against the expected worktree state
- can verify all the way back to the explicit zero baseline
Live data
Matey keeps live data separate from schema migrations.
Why:
- schema migrations change structure
- data files describe explicit current-state table contents
- data workflows stay easier to reason about than data hidden inside migration history
Each target can contain:
data/
data.toml
roles.jsonl
permissions.jsonl
data.toml declares one or more named data sets.
Example:
[core]
files = [
{ name = "roles", table = "roles", mode = "replace", order_by = ["id"] },
{ name = "permissions", table = "permissions", mode = "upsert", on = ["id"], order_by = ["id"] },
]
[demo]
files = [
{ name = "roles", table = "roles", mode = "replace", order_by = ["id"] },
{ name = "permissions", table = "permissions", mode = "upsert", on = ["id"], order_by = ["id"] },
{ name = "demo_users", table = "users", mode = "insert", order_by = ["id"] },
]
One file maps to one target table.
Supported data modes:
replace: target table contents become exactly the file contentsupsert: insert new rows and update existing rows by the declared key columnsinsert: append rows only
Why order_by matters:
- export needs deterministic row ordering
- otherwise repeated exports can churn in git for no semantic reason
Data commands:
matey data export --path db/core --set core
matey data apply --path db/core --set core
Both commands require the live database to already match the current worktree head schema.
SQLAlchemy codegen
Codegen is target-local and deterministic relative to the validated replay state. It does not introspect the live production database.
Target-local config:
[codegen]
enabled = true
generator = "tables"
# options = "..."
Generated file:
<target>/models.py
That means models.py is always derived from the same validated scratch replay that produced the schema artifacts.
It is regenerated automatically by schema apply when [codegen].enabled = true.
Non-goals
Matey intentionally does not try to be:
- Atlas-style migration autogeneration
- a declarative schema source-of-truth system
- a generic ETL/import/export framework
The source of truth remains:
- explicit SQL migrations
- committed schema artifacts
- explicit data manifests/files
Developer notes
This project bundles a compiled dbmate binary into the wheel at build time.
For development on this repository, use:
pixi install
Build hook:
build_hooks/build_dbmate.py
Useful environment variables:
MATEY_DBMATE_SOURCE=vendor|go-installMATEY_DBMATE_MODULE=...MATEY_DBMATE_VERSION=...MATEY_DBMATE_CGO_ENABLED=1|0MATEY_GO_LICENSES_MODULE=...MATEY_GO_LICENSES_VERSION=...MATEY_GO_LICENSES_DISALLOWED_TYPES=...MATEY_GO_LICENSES_ENFORCE=true|false
Per-platform wheel build notices are written under:
src/matey/_vendor/dbmate/<goos>-<goarch>/THIRD_PARTY_LICENSES/
License
Apache-2.0. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file matey-0.1.1.tar.gz.
File metadata
- Download URL: matey-0.1.1.tar.gz
- Upload date:
- Size: 22.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f07f35992187fe3065626d2fc0ddf9e72001cf40c90fcef2b3e80b35fcc7422a
|
|
| MD5 |
d1c459020632cc70bf1141b04f8ae68f
|
|
| BLAKE2b-256 |
d26b52449d08dbbf158f3cccdab492aa91a7c2210d177f24c889dd2c5b10c442
|
Provenance
The following attestation bundles were made for matey-0.1.1.tar.gz:
Publisher:
release.yml on unlap-hq/matey
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
matey-0.1.1.tar.gz -
Subject digest:
f07f35992187fe3065626d2fc0ddf9e72001cf40c90fcef2b3e80b35fcc7422a - Sigstore transparency entry: 1065872912
- Sigstore integration time:
-
Permalink:
unlap-hq/matey@9d20a1d7a10839718db1a24a6eac204368b53f01 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/unlap-hq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9d20a1d7a10839718db1a24a6eac204368b53f01 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file matey-0.1.1-py3-none-win_amd64.whl.
File metadata
- Download URL: matey-0.1.1-py3-none-win_amd64.whl
- Upload date:
- Size: 46.5 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
91b48d63a046db17765618734ee0209928990115d5ad0e8ed05d5e69c6e93768
|
|
| MD5 |
3a5e4c5edaa5d5eb34d0ae4bddcb90d5
|
|
| BLAKE2b-256 |
29baa7a045f41b006e1fea0d3c3b0db98090fcfb5c78c4976918042e96c75227
|
Provenance
The following attestation bundles were made for matey-0.1.1-py3-none-win_amd64.whl:
Publisher:
release.yml on unlap-hq/matey
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
matey-0.1.1-py3-none-win_amd64.whl -
Subject digest:
91b48d63a046db17765618734ee0209928990115d5ad0e8ed05d5e69c6e93768 - Sigstore transparency entry: 1065872997
- Sigstore integration time:
-
Permalink:
unlap-hq/matey@9d20a1d7a10839718db1a24a6eac204368b53f01 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/unlap-hq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9d20a1d7a10839718db1a24a6eac204368b53f01 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file matey-0.1.1-py3-none-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: matey-0.1.1-py3-none-manylinux_2_28_x86_64.whl
- Upload date:
- Size: 23.0 MB
- Tags: Python 3, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
551133234b1689feb58fe34d7cb331b7299fca2f8acddad8240e7ef97825c8eb
|
|
| MD5 |
bbee76caf0cf3570adade758d31dafb8
|
|
| BLAKE2b-256 |
71b615488f84dfd353668b1fb6ee6979423cc92efe063a0d525ea00aedec0d39
|
Provenance
The following attestation bundles were made for matey-0.1.1-py3-none-manylinux_2_28_x86_64.whl:
Publisher:
release.yml on unlap-hq/matey
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
matey-0.1.1-py3-none-manylinux_2_28_x86_64.whl -
Subject digest:
551133234b1689feb58fe34d7cb331b7299fca2f8acddad8240e7ef97825c8eb - Sigstore transparency entry: 1065872973
- Sigstore integration time:
-
Permalink:
unlap-hq/matey@9d20a1d7a10839718db1a24a6eac204368b53f01 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/unlap-hq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9d20a1d7a10839718db1a24a6eac204368b53f01 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file matey-0.1.1-py3-none-macosx_15_0_arm64.whl.
File metadata
- Download URL: matey-0.1.1-py3-none-macosx_15_0_arm64.whl
- Upload date:
- Size: 46.7 MB
- Tags: Python 3, macOS 15.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
44198ac30e36f05219012f5f008c52ffdb0c2921b167088ad8286ed88b83250d
|
|
| MD5 |
0c0e705fde38805ba5250fd2aca37954
|
|
| BLAKE2b-256 |
da9a34152b75d9c900783440f222742a889d6e94ab69814cf02a49f28008d145
|
Provenance
The following attestation bundles were made for matey-0.1.1-py3-none-macosx_15_0_arm64.whl:
Publisher:
release.yml on unlap-hq/matey
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
matey-0.1.1-py3-none-macosx_15_0_arm64.whl -
Subject digest:
44198ac30e36f05219012f5f008c52ffdb0c2921b167088ad8286ed88b83250d - Sigstore transparency entry: 1065872941
- Sigstore integration time:
-
Permalink:
unlap-hq/matey@9d20a1d7a10839718db1a24a6eac204368b53f01 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/unlap-hq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9d20a1d7a10839718db1a24a6eac204368b53f01 -
Trigger Event:
workflow_dispatch
-
Statement type: