Documentation
Everything you need to deploy, configure, and extend Crate.
Overview
Crate is a self-hosted music manager for collectors. It connects to music metadata providers (MusicBrainz, Deezer, or your own) to search and browse artists, then downloads tracks from Soulseek via slskd. Downloaded files are automatically organized, tagged with full metadata and cover art, and placed in your library.
The stack is a Go backend with SQLite, a React frontend, and standalone gRPC provider binaries — all shipped in a single Docker image.
Deployment
The recommended deployment is via Docker Compose with slskd as a sidecar. Crate needs a Soulseek account (provided through slskd) to download music.
# docker-compose.yml
services:
crate:
image: ghcr.io/theoutdoorprogrammer/crate:latest
ports:
- "6969:6969"
volumes:
- ./crate-data:/app/data # databases (crate.db, cache.db, activity.db)
- ./slskd/downloads:/app/downloads
- ./library:/app/library
environment:
- CRATE_SLSKD_URL=http://slskd:5030
- CRATE_SLSKD_API_KEY=your_api_key
- CRATE_DOWNLOADS_DIR=/app/downloads
- CRATE_LIBRARY_PATH=/app/library
- CRATE_DB_PATH=/app/data/crate.db
- CRATE_CACHE_PATH=/app/data/cache.db
- CRATE_ACTIVITY_PATH=/app/data/activity.db
depends_on:
- slskd
restart: unless-stopped
slskd:
image: slskd/slskd:latest
ports:
- "5030:5030"
volumes:
- ./slskd:/app
- ./library:/crate
environment:
- SLSKD_REMOTE_CONFIGURATION=true
- SLSKD_API_KEY=your_api_key
- SLSKD_SOULSEEK_USERNAME=your_username
- SLSKD_SOULSEEK_PASSWORD=your_password
restart: unless-stopped
CRATE_SLSKD_API_KEY must match the SLSKD_API_KEY you set for slskd. These two services communicate over the slskd REST API.
Volumes
Three volume mounts are important:
- Data directory — where Crate stores its SQLite databases. Map to a persistent path.
- Downloads directory — shared with slskd. Crate reads completed downloads from here. Must be the same path slskd writes to.
- Library directory — where organized, tagged music files end up. Point your media server (Navidrome, Plex, etc.) here.
Authentication
Crate does not include built-in authentication. It's designed to run behind your existing auth layer — a reverse proxy with basic auth, Authelia, Authentik, Cloudflare Access, a VPN, or whatever you prefer. If it's only accessible on your local network, no auth may be necessary.
Environment Variables
These are set at startup and control core paths, ports, and provider configuration. All have sensible defaults — only CRATE_SLSKD_API_KEY is required.
| Variable | Default | Description |
|---|---|---|
CRATE_PORT |
6969 |
HTTP port the web UI and API listen on. |
CRATE_DB_PATH |
./crate.db |
Path to the main SQLite database. |
CRATE_CACHE_PATH |
./cache.db |
Path to the provider cache database. Stores cached search results and metadata with a configurable TTL. |
CRATE_ACTIVITY_PATH |
./activity.db |
Path to the activity log database. Records download events, errors, and system events. |
CRATE_DOWNLOADS_DIR |
./downloads |
Directory where slskd places completed downloads. Crate reads from here. |
CRATE_LIBRARY_PATH |
./library |
Directory where organized music files are placed. Structure: Artist/Album/Track.ext |
CRATE_SCAN_INTERVAL |
6h |
How often the scheduler runs (new release detection, auto-queue, quality upgrades). Accepts Go duration strings: 30m, 6h, 24h, etc. |
CRATE_SLSKD_URL |
http://localhost:5030 |
Base URL of your slskd instance. |
CRATE_SLSKD_API_KEY |
none | API key for slskd. Required for downloads to work. |
CRATE_PROVIDERS |
musicbrainz:./provider-musicbrainz:50051,deezer:./provider-deezer:50052 |
Comma-separated list of providers. Format: name:binary:port. See Providers. |
CRATE_MB_USER_AGENT |
Crate/0.1.0 ... |
User-Agent string for MusicBrainz API requests. MusicBrainz requires a descriptive User-Agent. |
UI Settings
These settings are stored in the database and configurable from the Settings page in the web UI. Changes take effect immediately without restarting.
| Setting | Default | Description |
|---|---|---|
provider_primary |
musicbrainz |
Default provider for search and browse. Can be switched on the fly from the search UI. |
cache_ttl_hours |
24 |
How long provider search results and metadata are cached before re-fetching. |
quality_tiers |
FLAC > MP3 320 > MP3 256 |
Priority-ordered list of acceptable download formats. The downloader picks the highest-tier match from available sources. Stored as JSON. |
max_concurrent_slskd |
10 |
Maximum number of simultaneous downloads from Soulseek. |
max_auto_queue |
50 |
Maximum tracks the scheduler will auto-queue per cycle. Prevents flooding the download queue. |
requeue_cooldown_days |
7 |
Minimum days before a failed track can be re-queued by the scheduler. |
activity_retention_days |
30 |
How long activity log entries are kept before automatic cleanup. |
scan_interval |
from env | Override the scheduler interval at runtime (same format as CRATE_SCAN_INTERVAL). |
slskd_url |
from env | Override the slskd URL at runtime. |
slskd_api_key |
from env | Override the slskd API key at runtime. Treated as sensitive (masked in the UI). |
library_path |
from env | Override the library path at runtime. |
download_format_preference |
none | Preferred download format when multiple options are equivalent in quality tier. |
navidrome_url |
none | Base URL of your Navidrome instance. See Navidrome Integration. |
navidrome_user |
none | Navidrome username for triggering library scans. |
navidrome_password |
none | Navidrome password. Treated as sensitive (masked in the UI). |
slskd_url, slskd_api_key, library_path, and scan_interval can be set via environment variables at startup or overridden in the UI. The UI value takes precedence when set.
Providers
Providers supply music metadata (artist search, discography browsing, album/track details, cover art). Crate ships with two built-in providers and supports adding custom ones via gRPC.
Built-in Providers
| Provider | Source | Rate Limit | Notes |
|---|---|---|---|
| MusicBrainz | MusicBrainz.org API | 1 req/s | Open database. Best for completeness and accuracy. Default provider. |
| Deezer | Deezer public API | 10 req/s | Faster browsing, good cover art. Useful as a secondary provider. |
How Providers Work
- Default provider — set in settings as
provider_primary. Used for search and browse unless the user switches providers in the search UI. - Entity tracking — every artist, album, and track stores which provider and provider ID it came from. This is how Crate knows where to check for new releases.
- Provider switching — you can change the default provider at any time. Existing entities keep their original provider association.
- Relinking — any entity can be relinked to a different provider via the API. Useful if you switch primary providers and want to unify your library.
- Orphan detection — if a provider goes offline, entities from that provider show as “orphaned” in the UI.
- Caching — provider responses are cached in a separate SQLite database (
cache.db) with configurable TTL. The cache can be cleared from the Settings page.
Provider Configuration
The CRATE_PROVIDERS environment variable defines which providers to load. Format:
# Built-in providers (binary path relative to crate binary)
CRATE_PROVIDERS=musicbrainz:./provider-musicbrainz:50051,deezer:./provider-deezer:50052
# External provider (network address instead of binary path)
CRATE_PROVIDERS=musicbrainz:./provider-musicbrainz:50051,spotify:external:192.168.1.10:50053
Built-in providers are started as child processes by Crate. External providers connect to a remote gRPC server you run separately.
Download Flow
When you watch an artist, album, or track, here's what happens:
- Queuing — watched items are saved with status
wanted. The scheduler checks for new wanted tracks every scan interval. - Search — Crate searches slskd (Soulseek) for each wanted track, scoring results by quality tier, file format, and bitrate.
- Selection — the best result is selected based on your quality tiers. Blacklisted sources are excluded.
- Download — the file is downloaded via slskd. Track status changes to
downloading. The downloader checks progress every 10 seconds. - Organize — completed downloads are moved into the library with the naming convention
Artist/Album/Track.ext. - Tag — metadata (artist, album, track name, track number, year) and cover art are embedded into the file.
- Notify — if Navidrome is configured, a library scan is triggered. Track status becomes
owned.
Retry & Blacklist
Not every download succeeds on the first try. Crate handles failures automatically:
- No results — track stays
wanted. The scheduler will try again on the next cycle. - Transfer failure (rejected, errored, cancelled) — the specific username + filename pair is blacklisted. Future searches skip that source but can still find the track from other users.
- Retry backoff — failed downloads retry with increasing delays: 5m → 15m → 30m → 1h. After 4 attempts (~2 hours), the track reverts to
wantedfor the next scheduler cycle.
Concurrency
The max_concurrent_slskd setting (default 10) limits how many downloads run simultaneously. The max_auto_queue setting (default 50) caps how many tracks the scheduler adds per cycle, preventing the queue from growing unbounded.
Quality Upgrades
Crate continuously improves your library quality. The quality system works as follows:
- Quality tiers are priority-ordered in settings (default: FLAC > MP3 320 > MP3 256). Higher in the list = better.
- When a track is downloaded, its format and bitrate are recorded.
- The scheduler scans one artist per day (round-robin), checking if any owned tracks can be upgraded to a higher quality tier.
- Upgradeable tracks are re-queued automatically. The new download replaces the old file.
The requeue_cooldown_days setting (default 7) prevents the scheduler from re-queuing the same track too frequently if better quality isn't available yet.
Navidrome Integration
Crate can trigger a Navidrome library scan after each successful download, so new music appears in your streaming library immediately.
Setup
Configure these three settings in the Crate UI (Settings page):
| Setting | Example |
|---|---|
navidrome_url |
http://navidrome:4533 |
navidrome_user |
admin |
navidrome_password |
your_password |
All three fields are required. If any are empty, the Navidrome integration is silently disabled. Crate authenticates via the Subsonic API token+salt scheme.
CRATE_LIBRARY_PATH and Navidrome's music folder to the same directory (or use a shared volume). Crate organizes files into Artist/Album/Track.ext which Navidrome indexes automatically.
Supported Formats
| Format | Extension | Type |
|---|---|---|
| FLAC | .flac | Lossless |
| WAV | .wav | Lossless |
| MP3 | .mp3 | Lossy |
| Ogg Vorbis | .ogg | Lossy |
| Opus | .opus | Lossy |
| AAC | .aac | Lossy |
| MPEG-4 Audio | .m4a | Lossy |
The downloader recognizes all these formats when scoring search results. The tagger embeds metadata into FLAC (Vorbis comments) and MP3 (ID3v2) files. Cover art is embedded in both formats.
API Reference
Crate exposes a REST API on the same port as the web UI. All endpoints return JSON.
Status
| Method | Path | Description |
|---|---|---|
GET | /api/status | Health check and system status. |
Search & Browse
| Method | Path | Description |
|---|---|---|
GET | /api/search?q=&limit=&offset= | Search for artists via the active provider. Paginated. |
GET | /api/browse/artist/{id} | Browse an artist's full discography from the provider. |
GET | /api/browse/album/{id} | Browse an album's track listing from the provider. |
Library
| Method | Path | Description |
|---|---|---|
GET | /api/library/search?q= | Search your local library. |
GET | /api/artists | List all watched/owned artists. |
GET | /api/artists/{id} | Get artist details with albums. |
DELETE | /api/artists/{id} | Remove artist and all associated data. |
GET | /api/albums/{id} | Get album details with tracks. |
DELETE | /api/albums/{id} | Remove album. |
GET | /api/tracks/{id} | Get track details. |
DELETE | /api/tracks/{id} | Remove track. |
Watching
| Method | Path | Description |
|---|---|---|
POST | /api/watch/artist | Watch an artist (full discography tracking). |
POST | /api/watch/album | Watch a specific album. |
POST | /api/watch/track | Watch a specific track. |
Downloads
| Method | Path | Description |
|---|---|---|
GET | /api/downloads | List current download queue. |
POST | /api/downloads/{id}/retry | Retry a failed download. |
DELETE | /api/downloads/{id} | Cancel/remove a download. |
Providers
| Method | Path | Description |
|---|---|---|
GET | /api/providers | List all configured providers with health status. |
POST | /api/relink/artist/{id} | Relink an artist to a different provider. |
POST | /api/relink/album/{id} | Relink an album to a different provider. |
POST | /api/relink/track/{id} | Relink a track to a different provider. |
Settings & Activity
| Method | Path | Description |
|---|---|---|
GET | /api/settings | Get all settings (sensitive values masked). |
PUT | /api/settings | Update settings. |
GET | /api/activity?limit=&offset= | Get activity log. Paginated. |
DELETE | /api/cache | Clear the provider cache. |
Custom Providers
You can build your own metadata provider by implementing the gRPC service defined in proto/provider/provider.proto. The service interface includes:
SearchArtists— search by name, return ranked resultsGetArtist— full artist details with discographyGetAlbum— album details with track listingGetTrack— individual track details
Run your provider as a standalone gRPC server and add it to the CRATE_PROVIDERS env var:
CRATE_PROVIDERS=musicbrainz:./provider-musicbrainz:50051,my-provider:external:my-host:50053
Use the external keyword as the binary path to tell Crate it should connect to a remote server instead of launching a child process. Community-built providers and the database schema are documented in DATABASE.md.
Database
Crate uses three SQLite databases:
crate.db— main database. Artists, albums, tracks, settings, download queue, blacklist. WAL mode, single writer connection. Schema migrations via goose (embedded SQL files, run automatically on startup).cache.db— provider response cache with TTL. Can be safely deleted to force re-fetching, or cleared from the Settings page.activity.db— event log. Download completions, errors, scheduler actions. Auto-pruned based onactivity_retention_days.
The full database schema is documented in DATABASE.md in the repository.