Library / SDK
swingmx/swingmusic avatar
swingmx/swingmusic

Swing Music: a self-hosted player that normalizes your library before it plays it

Swing Music is a beautiful, self-hosted music player for your local audio files. Like a cooler Spotify ... but bring your own music.

2,059 stars135 forksPythonAGPL-3.0

At a glance

What is it?
Swing Music is an AGPL-3.0 Python music server that indexes local audio files, normalizes their metadata, and serves a browser UI on port 1970. Its main bet is that library cleanup is part of the player, not a separate chore.
Who is it for?
Adopt Swing Music if you have a local collection whose tags are inconsistent and you want the server itself to reconcile album versions and artist relationships. Do not adopt it if you need a documented public HTTP API for third-party clients, if you want a project where the README spells out every runtime flag, or if you cannot accept AGPL-3.0 terms for anything you plan to distribute.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 31 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem Swing Music picks: messy tags, not missing streams

Most self-hosted music servers assume your files are already correct. You point them at a folder, they read ID3 tags, and whatever is in those tags becomes the library. If half your collection says "Pink Floyd" and the other half says "Pink Floyd (Remastered)", you get two artists and two album entries, and no amount of browsing fixes it. Swing Music's README leads with metadata normalization as a feature, described as "a clean and consistent library", and pairs it with album versioning, which the README defines as "normalized albums and association with version labels (eg. Deluxe, Remaster, etc)". That is a different starting assumption: the server is expected to reconcile what it finds rather than display it verbatim. The audience follows from that. This is for someone with a few thousand local files accumulated over years, where the same record exists in three rips and the artist field has drifted. It is not aimed at someone streaming from a subscription service, and it is not aimed at someone with a small, carefully tagged collection who just wants a remote control for their speakers.

How the library gets normalized and served

The repository is Python, and the deployment model in the README is a single process serving a browser UI. Two volumes define the runtime boundary: `/music` for the audio and `/config` for the application's own state. That split matters because the config directory is where the normalized view of your library has to live for the normalization to be worth anything. If the index were rebuilt from raw tags on every start, the cleanup would be cosmetic. The README does not describe the index format or where it is written, so treat the persistence mechanism as unverified. What is documented is the surface: Daily Mixes generated from listening activity, related artists and albums, a folder view that bypasses the normalized view entirely, collections for grouping albums and artists manually, and statistics. The presence of both a normalized artist page and a folder view is the honest part of the design. Normalization will sometimes guess wrong, and the folder view is the escape hatch that shows the filesystem as it actually is. Silence detection is listed as a playback feature, combined with cross-fade, which means the server is doing audio analysis at playback time rather than only reading tags. Last.fm scrobbling and multi-user support are listed as features; the README does not state how accounts are created or where credentials are stored, so plan to discover that in the UI.

Installing it: the install script, Docker Compose, and the two environment variables

On Linux or macOS the README gives a single command: `curl -fsSL https://setup.swingmx.com | bash`. On Windows it points to a portable build on the downloads page. The default address is `http://localhost:1970`. The Docker Compose example in the README maps `1970:1970`, mounts `/path/to/music` at `/music` and `/path/to/config` at `/config`, and sets two environment variables: `SWINGMUSIC_PORT=1970` and `SWINGMUSIC_DEVICE_NAME=Host name here`. The README is explicit that the port must be changed in both places at once, for example `2001:2001` alongside `SWINGMUSIC_PORT=2001`, and the same warning is repeated for the `docker run` form. The image is `ghcr.io/swingmx/swingmusic:latest`, and the CLI example adds `--restart unless-stopped`. `SWINGMUSIC_DEVICE_NAME` is described as the name the server reports to connected clients, which is the kind of setting that only matters once you have more than one server or more than one client on the network. Beyond those two variables, the README defers to the docs for runtime option flags and notes that `-h` lists supported options. That is a thin installation surface, and thin is not the same as complete: the flags that do the interesting work (rescanning, reindexing, whatever triggers normalization) are not in the README.

Where the documented surface runs out

The README is a landing page, not a manual. It lists features and shows one Compose file. It does not document an HTTP API, does not describe how the library scan is triggered or scheduled, does not say what happens when a file's tags change after the first index, and does not explain how normalization resolves a conflict between two versions of the same album. Album versioning is a good example of an undocumented trade-off. Grouping a Deluxe edition under the same album as the original is useful for browsing, but it means the track list you see depends on a merge decision you cannot inspect from the README. If the merge is wrong, the folder view is your only documented recourse. The macOS situation is also worth reading carefully. The README's feature list says "Cross-platform - Windows, Linux, MacOS (coming soon), arm64, x86", while the installation section tells macOS users to run the bash install script. Those two statements are in tension, and the README does not resolve which one is current. Check the downloads page before assuming a Mac build exists. The Android client is a separate repository, which means mobile listening depends on a second project's release cadence rather than on a documented protocol.

Swing Music against Navidrome, and why the difference is the index

Navidrome is the obvious comparison for anyone running a self-hosted music server, and the difference is not the UI. Navidrome is built around the Subsonic API, which means the server's job is to expose a well-known interface that dozens of existing clients already speak. Swing Music's README does not mention Subsonic or any compatible API. Its client story is its own browser UI plus a first-party Android app in a separate repository. That is a real fork in the road. If your goal is to point a Subsonic client, a desktop player, or a home automation script at your library, Navidrome's approach fits that requirement and Swing Music's documented surface does not. If your goal is a single opinionated interface with normalization, Daily Mixes, and version grouping built in, Swing Music is doing work that a Subsonic server would leave to you or to your client. The cost is that you are adopting the interface along with the server. There is no documented way to swap the front end, and no documented way to bring your own. Pick based on whether you want a protocol or a product.

Licence and the cost of staying current

Swing Music is AGPL-3.0, stated as "AGPLv3 License or any later version". For someone running it on a home server for their own files, the practical effect is minimal. The copyleft obligations attach when you distribute the software or offer a modified version over a network. If you fork it, patch the normalization logic, and run that fork as a service other people reach, the AGPL's network clause is the part to read, and reading it is a job for a lawyer rather than for this article. The maintenance picture from the release list is active: v3.0.0 in June 2026, v2.1.10 in April 2026, v2.1.4 in January 2026, with the most recent push to the repository in August 2026. A major version bump between v2.1.10 and v3.0.0 is the thing to watch if you deploy this, because the README does not include a migration or upgrade section and does not say whether the `/config` volume carries forward across major versions. Back up that config directory before pulling a new tag. The README also states the project is "looking for contributors" and points to a Telegram group and a contributing guidelines file, which suggests a small maintainer group rather than a large one. That is not a reason to avoid it, but it is a reason to keep your own copy of the config and to test upgrades on a throwaway instance before touching the one your household uses.

What to confirm before you commit your library to it

Run the container against a copy of your music, not the original, and check three things. First, whether the normalized artist and album view produces entries you recognize, and whether the folder view still lines up with your directory structure when it does not. Second, whether the `/config` volume actually accumulates state, since that is the difference between a normalizing server and a pretty tag reader. Third, whether playback works for the formats you actually own; the README lists silence detection and cross-fade as features but says nothing about codec support, so the only way to know is to play a representative sample. If you are on macOS, confirm a build exists before you plan around the install script. If you want a Subsonic-compatible endpoint for other clients, this is not the project, and no amount of configuration will make it one. The judgement is narrow: Swing Music is worth the switch when inconsistent tags are the actual problem you have, and it is the wrong tool when the problem is that your existing clients cannot reach your files.

Editorial conclusion

Adopt Swing Music if you have a local collection whose tags are inconsistent and you want the server itself to reconcile album versions and artist relationships. Do not adopt it if you need a documented public HTTP API for third-party clients, if you want a project where the README spells out every runtime flag, or if you cannot accept AGPL-3.0 terms for anything you plan to distribute. Verify first that the browser UI handles your codec mix, that the config volume you mount actually contains the settings you expect after the first scan, and whether the Android client at github.com/swingmx/android covers the listening you actually do, because the README treats it as the mobile path rather than promising a general-purpose client API.

Official sources

  1. License: AGPL-3.0
  2. Project website
  3. README
  4. Releases
  5. swingmx/swingmusic on GitHub
Community notes

Community notes