Data model
Per-table field reference, with the source, owner and refresh cadence of every column.
Every table below lists each of its columns with a type, a description, and three pieces of provenance: where the value came from, what writes it, and how often that happens.
These pages are generated from a typed registry that lives beside the code, not written by hand. A migration that adds a column without registering it fails CI, so a field documented here exists, and a field that exists is documented here.
The tables
The reference covers the card database: the tables that hold the same values for everyone. They fall into six groups.
Cards
Card records and the printings they appear in, plus the registries of type words the parser recognises.
cards · card_popularity · card_printings · card_subtypes · mtg_card_types · mtg_supertypes · mtg_subtypes
Sets and products
Set metadata, the preconstructed decks shipped with a set and their contents, and sealed products.
sets · set_guides · precon_decks · precon_deck_cards · sealed_products
Prices
Current and historical prices. card_prices is per card; the rest are per
printing, at daily and weekly resolution.
card_prices · printing_prices_current · printing_price_daily · printing_price_weekly
Taxonomy
The curated concept vocabulary, the rules that detect each concept, and the associations those rules produce. See taxonomy for how the three fit together.
game_concepts · tag_detection_rules · card_concept_associations
Rules
Comprehensive rules text, per-card rulings, and worked examples.
game_rules · card_rulings · rules_examples
Operations
One row per data job run, recording what it consumed, what it matched, and when.
Your data
Decks, collections, conversations and profiles hold one person's rows rather than shared card data, so they live in your data. That section covers what each of those tables stores about you and who can read it.
Database functions
The database also carries functions the app calls directly. They are internal and undocumented. Publishing a list would imply an interface you can call from outside the app, and there is no such interface.
Source
Where a value originates, and therefore how much to trust it and who can change it.
| Source | Meaning |
|---|---|
scryfall | Imported from Scryfall bulk data. |
mtgjson | Imported from MTGJSON. |
unmaintained | Imported once and no longer refreshed. Read the timestamp beside the value. |
wotc | Official text from Wizards of the Coast, reproduced verbatim. Rules and rulings are never paraphrased, which is what makes them citable. |
wiki | Parsed from the MTG Fandom wiki. Community-maintained, so treat it as context rather than authority. |
calculated | Derived from other columns, by the database or a script. |
ai | Produced by a model, with the usual caveats. |
user | Entered by a person. Imports never overwrite it. |
Updated
How often the owning job refreshes the value.
| Cadence | Meaning |
|---|---|
on set release | Refreshed when a new set is seeded. |
daily / weekly | Refreshed on that schedule by a cron. |
on demand | Refreshed only when a pipeline is run manually. |
on write | Maintained by the database on every write. |
never | Set once when the row is created. |
Written by
The single job permitted to write that column. If a value looks wrong, this
names what to re-run. manual means the column is curated rather than imported:
there is nothing to re-run, and an import will not restore it.
Coverage
Every reference table in the schema is documented here. That is enforced rather than asserted: each table is classified as published, private, or unused, and a migration that adds one without classifying it fails to compile.
User and deck tables live in your data, which lists every one of them and links to its reference as each lands.
For what a value means rather than what type it is, see card data.