Skip to content

Importing MusicBrainz

The universe starts as artists. This guide takes a MusicBrainz full export and turns it into the artist, release_group and artist_url tables that every later stage builds on.

Nothing here touches a rate-limited API: the import reads a dump you already have on disk, so its speed is bounded by your machine and nobody’s quota.

MusicBrainz publishes full exports at data.metabrainz.org. Each export lives in a timestamped directory, and the LATEST file names the current one:

Terminal window
base=https://data.metabrainz.org/pub/musicbrainz/data/fullexport
version=$(curl -s $base/LATEST)
curl -O "$base/$version/mbdump.tar.bz2"

mbdump.tar.bz2 is the core archive — roughly 7 GB compressed. The other archives (edit history, statistics, cover art) are not needed: lyrid reads sixteen tables out of this one and skips the rest without decompressing them into memory. mbdump-derived.tar.bz2 is deliberately never downloaded — it is licensed CC BY-NC-SA, and ADR 0005 explains why that keeps it out of the canon.

Terminal window
lyrid import musicbrainz --dump ./mbdump.tar.bz2

The archive is read in a single pass — bzip2 has no random access, so a second pass would mean decompressing gigabytes again — and everything is written in one transaction. An interrupted import therefore leaves the previous universe intact rather than a half-replaced one.

Output looks like this:

INFO lyrid::import::musicbrainz: reading the MusicBrainz export dump=./mbdump.tar.bz2 size_mb=7042
INFO lyrid::import::musicbrainz: archive read; writing to PostgreSQL version=20260813-220122 artists=2958586 release_groups=4459412
INFO lyrid::import::musicbrainz: artists written rows=2958586
INFO lyrid::import::musicbrainz: release groups written rows=4402331 dropped=57081
INFO lyrid::import::musicbrainz: import complete version=20260813-220122

dropped counts release groups whose credited artist is not in the dump; importing them would leave albums floating outside any system.

The export version is taken from the TIMESTAMP file inside the archive and recorded in the database, so the universe can always say where it came from:

SELECT source, version, finished_at, rows_imported FROM dump_import;
source | version | finished_at | rows_imported
-------------+-----------------+-------------------------------+---------------
musicbrainz | 20260813-220122 | 2026-08-14 12:13:32.296058+00 | 7360917

Pass --dump-version to override it, for an archive repackaged without its timestamp.

Re-importing replaces the canon wholesale rather than merging into it: the same dump imported twice yields exactly the same tables, and a newer dump simply supersedes the older universe. Nothing user-owned lives in these tables, so there is no progress to lose.

Table From Notes
artist artist, artist_type, area, iso_3166_1 Type and country are flattened onto the row. area_code stays NULL where the area is not a country, rather than being guessed
release_group release_group, artist_credit_name, release, release_country, release_unknown_country Credited to the first artist in the credit. year is the earliest release year in the group, so a reissue never dates the album
artist_url l_artist_url, url, link, link_type Only artist→URL relationships

The artist_url table is what makes YouTube playback possible without the YouTube Data API: video and channel ids come from MusicBrainz relationships, so no API key and no quota are involved anywhere in the product. It is also how genres find their way in: the Discogs import joins on the discogs relationship stored here.

Release years are computed rather than read. MusicBrainz publishes a precomputed first_release_date_year in release_group_meta, but that table is not in this archive; the earliest date among a group’s releases is the same number, and computing it keeps the import to one download.