Skip to content

Navidrome

Navidrome is a modern self-hosted music server and streamer.

Description

It is a high-performance music server that allows you to listen to your music collection from any device. It is compatible with Subsonic/Madsonic API and provides a beautiful web interface.

What it is

Navidrome indexes a local music library, serves it through a responsive web UI, and exposes a Subsonic-compatible API for mobile and desktop music clients. It is lightweight enough for small home servers but still supports multi-user libraries, transcoding through ffmpeg, playlists, album art, and external clients.

What problem it solves

It turns a folder of owned audio files into a private streaming service. That avoids relying on commercial music subscriptions for personal collections, lets a household keep music available on the LAN/VPN, and gives automation scripts a stable API for library checks.

Where it fits in the stack

Navidrome belongs in the media services layer alongside Jellyfin and Audiobookshelf. In a home-office setup, it is usually deployed behind a reverse proxy, backed up with the rest of /data, and pointed at read-only music storage.

Typical use cases

  • Stream a FLAC/MP3 library to browsers, phones, and Subsonic-compatible clients.
  • Maintain family accounts with separate favorites, playlists, and playback state.
  • Keep a low-resource music service separate from a heavier video server.
  • Expose a music library over Tailscale or a private VPN without publishing file shares.

Strengths

  • Small operational footprint: Simple single-binary or single-container deployment.
  • Client compatibility: Works with many Subsonic-compatible apps.
  • Read-only media mounts: Easy to keep the app from modifying source music files.
  • Good homelab fit: Configuration can be managed through a TOML file or environment variables.

Limitations

  • Music-focused: It is not a full video/photo media platform.
  • Metadata-dependent: Poor tags lead to poor browsing results.
  • Transcoding dependency: ffmpeg must be available for some formats and clients.

When not to use it

Do not use Navidrome as a general media server for video, live TV, or photo libraries; use Jellyfin or Plex for those workloads. If you need audiobook-specific progress handling, chapter metadata, and podcast-style feeds, prefer Audiobookshelf.

Getting started

Docker Compose quick start

Create a data directory and point the music mount at an existing local music folder:

mkdir -p ./navidrome-data ./music
cat > docker-compose.yml <<'YAML'
services:
  navidrome:
    image: ghcr.io/navidrome/navidrome:latest
    container_name: navidrome
    user: "1000:1000"
    ports:
      - "4533:4533"
    restart: unless-stopped
    environment:
      ND_SCANSCHEDULE: "1h"
      ND_LOGLEVEL: "info"
      ND_SESSIONTIMEOUT: "24h"
    volumes:
      - ./navidrome-data:/data
      - ./music:/music:ro
YAML
docker compose up -d

Open http://localhost:4533, create the first admin user, and trigger or wait for the initial library scan.

Minimal configuration file

For non-container installs, a minimal navidrome.toml can be:

MusicFolder = "/srv/media/music"
DataFolder = "/var/lib/navidrome"
Address = "0.0.0.0"
Port = 4533
ScanSchedule = "1h"
LogLevel = "info"

CLI examples

# Follow startup and scan logs for the container
docker logs -f navidrome

# Confirm the web UI is listening on the default port
curl -I http://localhost:4533

# Check that the container can see mounted music files
docker exec navidrome find /music -maxdepth 2 -type f | head

API examples

Navidrome supports the Subsonic API. A basic ping request verifies that API authentication and the server endpoint are working:

: "${NAVIDROME_USER:?set NAVIDROME_USER to a Navidrome user}"
: "${NAVIDROME_PASSWORD:?set NAVIDROME_PASSWORD to that user's password}"
curl "http://localhost:4533/rest/ping.view?u=$NAVIDROME_USER&p=$NAVIDROME_PASSWORD&v=1.16.1&c=home-office&f=json"

Python health check using token authentication:

import hashlib
import secrets
import urllib.parse
import os
import urllib.request

base_url = os.environ.get("NAVIDROME_URL", "http://localhost:4533")
username = os.environ["NAVIDROME_USER"]
password = os.environ["NAVIDROME_PASSWORD"]
salt = secrets.token_hex(6)
token = hashlib.md5(f"{password}{salt}".encode()).hexdigest()
query = urllib.parse.urlencode({
    "u": username,
    "t": token,
    "s": salt,
    "v": "1.16.1",
    "c": "home-office-check",
    "f": "json",
})
with urllib.request.urlopen(f"{base_url}/rest/ping.view?{query}", timeout=10) as response:
    print(response.read().decode())

Troubleshooting

  • If the UI starts but no albums appear, verify Linux permissions with ls -n ./music and make the Compose user match the folder owner.
  • If remote clients cannot connect, confirm port 4533 is reachable through the firewall, VPN, or reverse proxy.
  • If some files do not play, install or expose ffmpeg and check whether the client requires transcoding for that format.
  • If playlists are missing, create the admin user first, then touch .m3u files or trigger a rescan.

Alternatives

Backlog

  • Integrate with "Audiobookshelf" for a unified audio library.

Sources / References

  • https://www.navidrome.org/
  • https://www.navidrome.org/docs/installation/
  • https://www.navidrome.org/docs/getting-started/
  • https://github.com/navidrome/navidrome
  • https://airsonic.github.io/

Contribution Metadata

  • Confidence: high
  • Last reviewed: 2026-05-06