MTG Cheaper Deck works entirely from a local SQLite database rather than querying Scryfall’s search API at analysis time. The sync scriptDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/invvd/mtg-cheaper-deck/llms.txt
Use this file to discover all available pages before exploring further.
sync_scryfall.py populates that database by downloading Scryfall’s pre-built Oracle Cards bulk export — one compressed file containing every unique card face, including prices, legalities, keywords, and oracle text. Fetching a single ~40 MB file once is orders of magnitude faster and friendlier to Scryfall’s infrastructure than issuing individual card lookups for an entire deck. Prices and legalities in the local database stay accurate as long as you re-run the sync regularly — daily is recommended.
Running the Sync
What It Does
Fetch the bulk-data metadata
The script calls
https://api.scryfall.com/bulk-data/oracle-cards to retrieve the current metadata object for the Oracle Cards dataset. It reads the jsonl_download_uri field from the response to get the actual download URL for the current snapshot.Download the compressed card file
The
.jsonl.gz file (approximately 40 MB compressed) is downloaded in streaming 1 MB chunks to ./data/oracle-cards.jsonl.gz. A progress percentage is printed to the console as chunks arrive.Stream and parse card objects
The gzip file is opened in text mode and read line by line. Each line is a complete JSON object representing one Oracle card. Streaming avoids loading the entire decompressed file into memory at once.
Upsert in batches of 1,000
Parsed card dicts are accumulated into a batch. When the batch reaches 1,000 entries, it is committed to the database with a single
INSERT ... ON CONFLICT DO UPDATE statement targeting the oracle_id primary key. This keeps individual transactions small and allows the running count to update incrementally on the console.Skip entries without an oracle_id
Any JSON object that lacks an
oracle_id field is skipped and counted separately. If any entries were skipped, the final output prints a notice with the count. Cards without an oracle_id cannot be used as a stable deduplication key and would corrupt the upsert logic.Data Extracted per Card
Thecard_to_dict() function maps each Scryfall JSON object to the columns of the local cards table:
| Column | Source field | Notes |
|---|---|---|
oracle_id | oracle_id | Primary key; stable across printings |
scryfall_id | id | The specific printing Scryfall chose as representative |
name | name | |
color_identity | color_identity | JSON array, e.g. ["U", "B"] |
color_identity_mask | computed | Bitmask: W=1, U=2, B=4, R=8, G=16 |
type_line | type_line | Full type line including subtypes |
cmc | cmc | Converted mana cost as a float |
keywords | keywords | JSON array of Scryfall keyword strings |
oracle_text | oracle_text | Falls back to joined card faces (see below) |
power | power | Falls back to card_faces[0].power |
toughness | toughness | Falls back to card_faces[0].toughness |
price_usd | prices.usd | Cast to float; None if absent or non-numeric |
legalities | legalities | Full legalities dict stored as JSON |
edhrec_rank | edhrec_rank | Integer; absent cards stored as None |
updated_at | released_at | Date string of the card’s original release |
oracle_text (common for transform and modal double-faced cards), the text from all card_faces entries is joined with \n//\n to produce a single combined oracle text string. For power and toughness, the fallback reads from card_faces[0] only.
Scheduling a Daily Sync
Scryfall updates its bulk exports roughly once a day. Prices in particular can shift significantly day to day. To keep your local data current, add a crontab entry that runs the sync automatically:crontab -e
./data/sync.log for easy review.
Scryfall API Compliance
The sync script identifies itself to Scryfall using the User-Agent string
MTGCheaperDeck/0.1 (https://github.com/; contacto de desarrollo personal), as recommended by Scryfall’s API guidelines. The tool never calls Scryfall’s per-card search endpoint — that endpoint is rate-limited to approximately 10 requests per second and is unnecessary when the full Oracle Cards bulk file is available. One bulk download covers all ~38,000 cards in a single request.Re-Sync Is Safe
The upsert operation is fully idempotent. Re-runningsync_scryfall.py at any time — even immediately after a previous run — updates every column for any oracle_id already present in the database and inserts rows for any new cards. No duplicate rows are created. The only observable difference between two identical runs is that prices and legalities reflect the latest Scryfall snapshot.