Navidrome (music)

Navidrome scans library/music, keeps the music database and serves the songs. SoundStorm talks to it over the Subsonic API (with OpenSubsonic extensions) and builds albums, radio, lyrics and beat analysis on top.

Why Navidrome

Jellyfin could serve music too, but its music support is a second-class citizen next to its video support, structurally. Navidrome gets multi-value artist tags, album artist versus artist, compilations, ReplayGain, smart playlists and a fast scanner right - exactly the music engine a fork of a media server would have meant rebuilding by hand. Its image is about 348 MB against Jellyfin's 2.5 GB.

Provisioning

Navidrome's first-run admin form posts to /auth/createAdmin, and that endpoint works only while no user exists - so driving it is safe: it can never take over a configured server. SoundStorm generates the password, creates the admin, and keeps the credentials in its state. The music folder is mounted read-only. Compose sets a few environment variables, and their names matter:

SettingWhy
ND_SCANINTERVAL: 1mNot ND_SCANSCHEDULE. Navidrome ignores unknown keys silently, so the wrong name looked like it worked while no periodic scan ever ran. Check --help in the container before trusting any of these names.
ND_SUBSONIC_DEFAULTREPORTREALPATHReport real file paths rather than ones built from tags (below).
ND_ENABLETRANSCODINGCONFIGLets SoundStorm add its own listening transcoding for beat analysis; without it the API answers 405.
ND_ENABLEEXTERNALSERVICES: falseNothing leaves the house from Navidrome itself.

The household shares this one account. Favorites, playlists and history are kept by SoundStorm per person, because anything stored in Navidrome would be everybody's at once. A second, non-admin account, audiomuse, is made through Navidrome's native /api/user for AudioMuse-AI.

The calls SoundStorm makes

Every request carries Subsonic token authentication: a fresh salt and the MD5 of password plus salt, in the query string. That is the protocol - and why transport errors are passed through httpx.Redact before anyone sees them, since the URL carries a credential.

CallUsed for
search3Search, and browsing the whole song shelf (an empty query returns everything)
streamSongs, with maxBitRate and format=mp3 for data saver, and the listening transcoding for beats
getCoverArtCovers, resized by Navidrome to the size asked
getSongOne song by id, and its real path for deletion
getAlbum, getArtistResolving old tag-based album and artist ids
getRandomSongs, getGenresLibrary mixes
getLyricsBySongIdLocal lyrics, synced from a .lrc beside a song
startScan"Look now" after an upload - the quick kind, cheap enough to fire per drop

Verified quirks

Albums from folders

Navidrome groups albums by tags, which on a real library made 1,467 albums out of 551 album folders. The adapter's folders.go regroups Navidrome's own song list by path - artist folder, album folder, discs inside - with ids f: plus the folder path. See Music.

Deleted files

Navidrome is the one backend that needed no help: a deleted file's row is flagged missing and dropped from search3 by Navidrome itself. Its database can hold dozens of tracks for an empty folder while answering search with none of them, which is exactly right.

Version

The image follows latest; behaviours above were checked against 0.64.0 and 0.64.1. Re-verify the environment names and the transcoding API if the version moves.