Crate separates music metadata from the core application through a gRPC plugin system. Every metadata source — MusicBrainz, Deezer, or anything you build — is a standalone process that implements theDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/TheOutdoorProgrammer/crate/llms.txt
Use this file to discover all available pages before exploring further.
MusicProvider gRPC service. Crate either starts these processes itself and manages their lifecycle, or connects to ones already running on the network. From Crate’s perspective every provider is equal: search results, artist pages, discographies, and the upgrade scanner all work identically regardless of which provider backs them.
The
MusicProvider service is defined in proto/provider/provider.proto using proto3. Any language with a gRPC code generator — Go, Python, TypeScript, Rust, Java, and more — can implement it.The gRPC Contract
Your provider implements theMusicProvider service:
RPC Reference
| RPC | Purpose |
|---|---|
Info | Return provider name, display name, and version. Called on registration and on every health check. |
SearchArtists | Search for artists by name. Supports limit and offset for pagination. Return total for the full result count. |
GetArtist | Return artist details by provider-specific ID. |
GetArtistAlbums | List all albums and releases for an artist. |
GetAlbum | Return album details including the full track listing. |
SearchArtistTracks | Search tracks within a specific artist’s catalog by query string. |
Key Fields
IDs are plain strings. Use whatever your source API returns — MBIDs, Deezer int64s cast to strings, Spotify URIs, anything. Crate stores them opaquely and only uses them for cache keys, deduplication, and live lookups.rank controls display order on search results, album lists, and track lists. Higher rank means shown first. MusicBrainz uses search relevance score; Deezer uses fan count. Any integer works.
metadata is a map<string, string> field present on every entity message (ArtistResult, ArtistDetail, AlbumSummary, AlbumDetail, TrackInfo). Put anything useful here — country, disambiguation, genre, fan count, release date — and the frontend renders each entry as an info tag. No schema registration needed.
record_type on AlbumSummary should be one of album, single, ep, or compilation. The frontend displays this as a badge next to the album title.
Running Your Provider
- Managed child process
- External process
Crate starts the binary for you and passes the port via environment variable. Set On startup Crate:
CRATE_PROVIDERS to a comma-separated list of name:binary:port entries:- Launches each binary with
PORT=<port>in its environment. - Waits up to 10 seconds for the gRPC server to respond to
Info(). - Registers the provider using the name returned by
Info().
0.0.0.0:<PORT> (or localhost:<PORT>) and be ready to serve before the timeout expires.Minimal Go Implementation
The example below is a working, compilable provider skeleton. Embed your API calls insideSearchArtists, GetArtist, GetArtistAlbums, GetAlbum, and SearchArtistTracks.
Caching and Rate Limiting
Response caching
Crate caches every provider response in a separate SQLite database (
cache.db). Cache keys are namespaced by provider name — myprovider:artist:123 — so providers never collide. Users can clear the cache and adjust the TTL (default 24 hours) from the Settings page.Rate limiting
If your upstream API has rate limits, enforce them inside your provider process. Crate’s cache layer significantly reduces repeat calls during normal use, but your provider should still apply its own token-bucket or leaky-bucket limiter for burst protection. See
golang.org/x/time/rate for a lightweight Go implementation.Health Checks and Recovery
Crate periodically callsInfo() on every registered provider with a 2-second timeout. If the call fails, all artist and album entities linked to that provider show an orphaned indicator in the UI. No data is lost — the rows remain in the database. When the provider comes back online and Info() succeeds again, the orphaned indicator clears automatically.
Users can also manually relink any artist to a different provider (for example, switching from a failing custom provider to musicbrainz) without losing any library data.
Provider Configuration Reference
CRATE_PROVIDERS format
CRATE_PROVIDERS format
Each entry in the comma-separated list follows one of two formats:
| Mode | Format | Example |
|---|---|---|
| Managed process | name:binary_path:port | myprovider:./my-provider:50053 |
| External process | name:external:host:port | myprovider:external:10.0.0.5:50053 |
name must be unique and must not be local (reserved for the library importer).InfoResponse fields
InfoResponse fields
Info() is called both at startup (registration) and repeatedly as a health check. Keep the implementation fast and stateless.| Field | Type | Notes |
|---|---|---|
name | string | Machine-readable identifier; should match the name in CRATE_PROVIDERS |
display_name | string | Human-readable label shown in the UI provider selector |
version | string | Semver or any string; shown in the Settings providers list |
SearchRequest pagination
SearchRequest pagination
SearchArtists receives limit and offset integers. Return the full total count (not just the current page size) so the UI can render correct pagination controls. If your API does not support offset pagination, return total equal to len(artists) in each response.