This page is for developers looking to learn more about Navidrome. For information about contributing to Navidrome, see the Navidrome Contribution Guide.
This is the multi-page printable view of this section. Click here to print.
Developers
- 1: Development Environment
- 2: Creating New Themes
- 3: Translations
- 4: Adding Client Apps to the Catalog
- 5: Subsonic API Compatibility
1 - Development Environment
This is just a summary on how to get started. If you are stuck or have any questions, please join our Discord server and give us a shout on the #dev channel
Any IDE with good support for GoLang and JavaScript/Node can be used for Navidrome development. We suggest using Visual Studio Code, which has excellent support for both languages.
Using VSCode + Dev Container (Docker)
The project includes a VSCode Dev Container configuration for using with Docker. The Dev Container provides all dependencies out-of-the-box. If you prefer to install all dependencies yourself, or cannot/don’t want to install Docker for any reason, see the other sections below for step by step instructions for your OS.
Note
Keep in mind that the overall experience when using Docker Desktop for development will be slower than normal, because access to the host OS filesystem is generally slower. If you want to have full performance, we recommend installing the dependencies directly on your system and skip using Docker for development.Unix-based systems (Linux, macOS, BSD, …)
-
Install GoLang 1.23+
-
Install Node 20
-
Install TagLib 2.0+
- Arch Linux:
pacman -S taglib - macOS:
brew install taglib --HEAD - For other platforms check their installation instructions
- Arch Linux:
-
Install
pkg-config -
Clone the project from https://github.com/navidrome/navidrome
-
Install development tools:
make setup. This may take a while to complete -
Test installation:
make build. This command should create anavidromeexecutable in the project’s folder -
Create a
navidrome.tomlconfig file in the project’s folder with (at least) the following options:
# Set your music folder, preferable a specific development music library with few songs,
# to make scan fast
MusicFolder = "/path/to/music/folder"
# Make logging more verbose
LogLevel = "debug"
# This option will always create an `admin` user with the specified password, so you don't
# have to create a user every time you delete your dev database
DevAutoCreateAdminPassword = "password"
# Move the data/DB folder out of the root. `./data` folder is ignored by git
DataFolder = "./data"
# If you are developing in macOS with its firewall enabled, uncomment the next line to avoid
# having to accept incoming network connections every time the server restarts:
# Address = "localhost"
To start Navidrome in development mode, just run make dev. This will start both the backend
and the frontend in “watch” mode, so any changes will automatically be reloaded. It will open
Navidrome automatically in your browser, using the URL http://localhost:4533/
If it does not open a new window in your browser, check the output for any error messages.
For more useful make targets, run make help.
Building it locally
To build Navidrome locally, follow these steps:
- Make sure you have all the dependencies installed as mentioned in the previous sections.
- Open a terminal and navigate to the project’s folder.
- Run the command
make buildto build the whole project. This will create anavidromebinary in the project’s folder
Building with Docker
If you want to build Navidrome for a different platform than your own dev environment, use make docker-build and specify the OS/Platform as parameters. Example for Windows/386:
make docker-build PLATFORMS=windows/386
To get a list of all available platforms, run make docker-platforms.
If you want to build a Docker image with your local changes, use make docker-image.
The built image will be tagged locally as deluan/navidrome:develop. This can be overridden by setting the DOCKER_TAG variable.
Use IMAGE_PLATFORMS to specify the platforms you want to build the image for. Example:
make docker-image IMAGE_PLATFORMS=linux/amd64,linux/arm64 DOCKER_TAG=mytag
Windows (using WSL)
Even though it is possible to setup a fully working Navidrome development environment in Windows, we currently don’t provide instructions for that (feel free to contribute to these docs if you successfully set it up).
The (arguably better) alternative is to set up the project using Visual Studio Code and WSL, which effectively lets you develop in a Linux environment while still using your Windows system.
Installing WSL
- Make sure your Windows 10 is updated.
- Go to Settings > Turn Windows feature on or off > Windows subsystem for Linux.
- Go to Microsoft Store and download and install any Linux distro you like. For maximum compatibility, we recommend Ubuntu.
- Open Downloaded Linux distro, add username and password and then update it using:
sudo apt update && sudo apt upgrade -y. - Install needed compilers for building Navidrome:
sudo apt install gcc g++ - This will create an Linux terminal where you can execute any Linux commands.
Make sure you are using WSL 2.0
Configuring Visual Studio Code
- Click on Extensions (present on leftmost column), install Remote Development extension and reload VSCode.
- Press F1, execute Remote-WSL: New Window. This will connect your installed Linux distro to VSCode.
- Now you can open a VSCode terminal and you’ll be able to run any Linux command.
Common Issues
- Because of this WSL issue you need to use your network IP address to be able to login to Navidrome in development mode. Otherwise you will get an
Error: Unauthorizedwhen logging in. You can see your network IP address after runningmake dev.
Now that you have a working instance of Linux running on your machine, follow the steps above for Unix-based system in the VSCode terminal. For more information on working with VSCode+WSL, check their documentation.
Troubleshooting
System limit for number of file watchers reached
If you encounter the Error: ENOSPC: System limit for number of file watchers reached, watch while running make dev on Linux systems, then your system is maxing out the number of files that can be “watched” for changes at one time.
To increase this limit, you can run the command echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p, which adds the line fs.inotify.max_user_watches=524288 to /etc/sysctl.conf and reloads sysctl so the change takes effect. this allows inotify to watch more files and folders for changes at a time.
More information about this can be found here
2 - Creating New Themes
Themes in Navidrome are simple Material-UI themes. They are basic JS objects, that allow you to override almost every visual aspect of Navidrome’s UI.
Steps to create a new theme:
- Create a new JS file in the
ui/src/themesfolder that exports an object containing your theme. Create the theme based on the ReactAdmin/Material UI documentation below. See the existing themes for examples. - Add a
themeNameproperty to your theme. This will be displayed in the theme selector - Add your new theme to the
ui/src/themes/index.jsfile - Start the application, your new theme should now appear as an option in the theme selector
Before submitting a pull request to include your theme in Navidrome, please test your theme thoroughly and make sure
it is formatted with the Prettier rules found in the project (ui/src/.prettierrc.js).
Also, don’t forget to add lots of screenshots!
Resources for Material-UI theming
- Start reading ReactAdmin documentation
- Color Tool: https://material-ui.com/customization/color/#official-color-tool
3 - Translations
Translations are currently managed in POEditor.
If you want to contribute new translations or help reviewing/proofreading any of the existing
ones, please join our Discord server, channel #translations, for
translation efforts coordination and to get further instructions.
Contributing with a Pull Request
Alternatively, you can submit a pull request with your proposed changes directly to our project in GitHub. This method requires you to have a GitHub account and some basic knowledge of Git.
If you choose to contribute translations via a pull request, most of the translation files are located in the resources/i18n directory. The English translation file is the only one located outside of this directory. It can be found in the ui/src/i18n/en.json.
Translation Status
Languages with at least 70% of the terms translated:
| Language | Code | Progress | Last Updated |
|---|---|---|---|
|
|
ar | 70.95% | 2023-03-26 |
|
|
eu | 100.00% | 2025-12-19 |
|
|
bs | 98.76% | 2025-07-29 |
|
|
bg | 83.61% | 2025-12-06 |
|
|
ca | 80.71% | 2025-04-17 |
|
|
zh-Hans | 98.76% | 2025-11-07 |
|
|
zh-Hant | 98.76% | 2025-11-07 |
|
|
cs | 71.78% | 2023-08-06 |
|
|
da | 100.00% | 2025-11-17 |
|
|
nl | 100.00% | 2025-12-03 |
|
|
en | 100.00% | 2025-11-15 |
|
|
eo | 100.00% | 2025-12-03 |
|
|
et | 100.00% | 2025-11-16 |
|
|
fi | 100.00% | 2025-12-06 |
|
|
fr | 100.00% | 2025-12-01 |
|
|
gl | 100.00% | 2025-12-03 |
|
|
de | 100.00% | 2025-11-17 |
|
|
el | 100.00% | 2025-11-20 |
|
|
hi | 98.76% | 2025-07-28 |
|
|
hu | 99.38% | 2025-12-02 |
|
|
id | 98.76% | 2025-07-19 |
|
|
ja | 100.00% | 2025-11-21 |
|
|
ko | 98.55% | 2025-11-07 |
|
|
no | 81.54% | 2025-12-02 |
|
|
pl | 100.00% | 2025-11-16 |
|
|
pt-br | 100.00% | 2025-11-15 |
|
|
ru | 100.00% | 2025-11-24 |
|
|
sr | 80.71% | 2025-04-17 |
|
|
sl | 100.00% | 2026-01-06 |
|
|
es | 100.00% | 2025-12-01 |
|
|
sv | 100.00% | 2025-11-17 |
|
|
th | 100.00% | 2025-11-21 |
|
|
tr | 100.00% | 2025-12-02 |
|
|
uk | 100.00% | 2025-11-17 |
|
|
vi | 100.00% | 2025-12-11 |
|
|
yi | 73.86% | 2025-03-25 |
4 - Adding Client Apps to the Catalog
Want to list your app in the Compatible Client Apps catalog? This guide explains how to submit your app or update an existing entry.
Prerequisites
- Your app must support the OpenSubsonic, Subsonic, or Navidrome API
- You’ll need a GitHub account to submit a pull request
- Images must be in WebP format, max 1200px (PNG/JPEG needs to be converted)
Quick Start
- Fork the navidrome/website repository
- Create a folder for your app in
assets/apps/using kebab-case (e.g.,my-awesome-app) - Add an
index.yamlfile with your app’s metadata - Add a thumbnail image and optional gallery screenshots
- Convert (or resize) images if needed:
npm run convert:images my-awesome-app - Validate your entry using the provided scripts:
npm run validate:app my-awesome-app - Submit a pull request
Folder Structure
Each app has its own folder under assets/apps/:
assets/apps/
my-app/
index.yaml # App metadata (required)
thumbnail.webp # App thumbnail (required)
screen1.webp # Gallery screenshot (optional)
screen2.webp # Gallery screenshot (optional)
Creating index.yaml
Use the template at assets/apps/_template/index.yaml as a starting point.
Required Fields
| Field | Description |
|---|---|
name |
Display name of your app |
url |
Official app website or homepage |
platforms |
At least one platform (see below) |
api |
Supported API: OpenSubsonic, Subsonic, or Navidrome |
description |
Brief description (1-2 sentences) |
screenshots.thumbnail |
Filename of thumbnail image |
Optional Fields
| Field | Description |
|---|---|
repoUrl |
Repository URL (GitHub, GitLab) - used for release date tracking |
isOpenSource |
Whether the source code is publicly available (see below) |
isFree |
Whether the app is free (no purchase required) - boolean |
keywords |
Additional search terms (max 6) - not displayed on app card |
screenshots.gallery |
Array of additional screenshot filenames |
platforms.*.store |
Platform-specific store URLs |
Open Source vs Repository URL
The repoUrl field is used to fetch the app’s last release date. If your app has a GitHub or GitLab repository, include it for accurate “last updated” information.
The isOpenSource field controls whether the app displays an open source badge and appears in the “Open Source Only” filter:
- If
repoUrlis set andisOpenSourceis omitted → app is treated as open source (default) - If
repoUrlis set andisOpenSourceisfalse→ app is NOT treated as open source - If
repoUrlis not set → app is NOT treated as open source (regardless ofisOpenSource)
Use isOpenSource: false when your app has a GitHub/GitLab repository for releases or issue tracking, but the source code is not publicly available under an open source license.
Supported Platforms
android- Google Play Storeios- Apple App Storemacos- macOS (optionally with Mac App Store link)windows- Windowslinux- Linuxweb- Web browserdocker- Docker container (optionally with Docker Hub link)other- CLI tools, other platforms
Example index.yaml
name: My Music App
url: https://example.com/my-app
repoUrl: https://github.com/example/my-app # Optional - used for release tracking
# isOpenSource: false # Uncomment if repo exists but source code is not public
platforms:
android:
store: https://play.google.com/store/apps/details?id=com.example.myapp
ios:
store: https://apps.apple.com/app/my-app/id123456789
web: true
linux: true
api: OpenSubsonic
description: A beautiful music player with offline support and gapless playback.
screenshots:
thumbnail: thumbnail.webp
gallery:
- screen1.webp
- screen2.webp
keywords:
- dlna
- chromecast
- carplay
- android auto
Image Guidelines
Thumbnail (Required)
- Max size: 1200×1200px
- Aspect ratio: Square preferred
- Format: WebP (PNG/JPEG needs to be converted)
Gallery Images (Optional)
- Max size: 1200×1200px
- Aspect ratio: Any
- Format: WebP (PNG/JPEG needs to be converted)
- File size: Keep under 500KB per image
Processing Images
If your images don’t meet the guidelines, run the conversion script:
npm run convert:images my-app
This automatically converts images to WebP format, resizes them to max 1200px, and optimizes file sizes.
Validating Your Entry
Before submitting, validate your app entry:
npm run validate:app my-app
The validation checks:
- YAML syntax and structure
- Required fields are present
- APIs are correctly specified
- Image files exist
- URLs are valid and reachable
- File sizes (warns if images > 500KB)
Updating an Existing App
To update an existing app entry:
- Find the app folder in
assets/apps/ - Modify the
index.yamlor replace images as needed - Run validation and submit a pull request
Questions?
If you have questions about adding your app, please open an issue on GitHub.
5 - Subsonic API Compatibility
Supported Subsonic API endpoints
Navidrome is currently compatible with Subsonic API v1.16.1, with some exceptions.
OpenSubsonic extensions are being constantly added. For an up to date list of supported extensions, check here.
This is a (hopefully) up-to-date list of all Subsonic API endpoints implemented in Navidrome. Check the “Notes” column for limitations/missing behavior. Also keep in mind these differences between Navidrome and Subsonic:
- Navidrome will not implement any video related functionality, it is focused on Music only
- Navidrome supports multiple Music Libraries (Music Folders) with user-specific access controls
- There are currently no plans to support browse-by-folder. Endpoints for this functionality (Ex:
getIndexes,getMusicDirectory) returns a simulated directory tree, using the format:/Artist/Album/01 - Song.mp3. - Navidrome does not mark songs as played by calls to
stream, only whenscrobbleis called withsubmission=true - IDs in Navidrome are always strings, normally MD5 hashes or UUIDs. This is important to mention because, even though the Subsonic API schema specifies IDs as strings, some clients insist in converting IDs to integers
| System | |
|---|---|
ping |
|
getLicense |
Always valid ;) |
| Browsing | |
|---|---|
getMusicFolders |
Returns all libraries accessible to the authenticated user |
getIndexes |
Doesn’t support shortcuts, nor direct children |
getMusicDirectory |
|
getSong |
|
getArtists |
|
getArtist |
|
getAlbum |
|
getGenres |
|
getArtistInfo |
Requires external integrations |
getArtistInfo2 |
Requires external integrations |
getAlbumInfo |
Requires external integrations |
getAlbumInfo2 |
Requires external integrations |
getTopSongs |
Requires Last.fm integration |
getSimilarSongs |
Requires Last.fm integration |
getSimilarSongs2 |
Requires Last.fm integration |
| Album/Songs Lists | |
|---|---|
getAlbumList |
|
getAlbumList2 |
|
getStarred |
|
getStarred2 |
|
getNowPlaying |
|
getRandomSongs |
|
getSongsByGenre |
| Searching | |
|---|---|
search2 |
Doesn’t support Lucene queries, only simple auto complete queries |
search3 |
Doesn’t support Lucene queries, only simple auto complete queries |
| Playlists | |
|---|---|
getPlaylists |
username parameter is not implemented |
getPlaylist |
|
createPlaylist |
|
updatePlaylist |
|
deletePlaylist |
| Media Retrieval | |
|---|---|
stream |
|
download |
Accepts ids for Songs, Albums, Artists and Playlists. Also accepts transcoding options similar to stream |
getCoverArt |
|
getLyrics |
Works with embedded lyrics and external files |
getAvatar |
If Gravatar is enabled and the user has an email, returns a redirect to their Gravatar. Or else returns a placeholder |
| Media Annotation | |
|---|---|
star |
|
unstar |
|
setRating |
|
scrobble |
| Bookmarks | |
|---|---|
getBookmarks |
|
createBookmark |
|
deleteBookmark |
|
getPlayQueue |
current is a string id, not int as it shows in the official Subsonic API documentation |
savePlayQueue |
Sharing (if EnableSharing is true) |
|
|---|---|
getShares |
|
createShare |
|
updateShare |
|
deleteShare |
| Internet radio | |
|---|---|
getInternetRadioStations |
|
createInternetRadioStation |
|
updateInternetRadioStation |
|
deleteInternetRadioStation |
| User Management | |
|---|---|
getUser |
Ignores username parameter, and returns the user identified in the authentication. Roles reflect actual server capabilities and user permissions. For example: downloadRole depends on download being enabled, jukeboxRole depends on jukebox being enabled, etc. Note that some features like ratings and favorites are always available to all users regardless of roles |
getUsers |
Returns only the user identified in the authentication |
| Media library scanning | |
|---|---|
getScanStatus |
Also returns the extra fields lastScan and folderCount |
startScan |
Accepts an extra fullScan boolean param, to force a full scan |