# Iris is a browser front end for a Mopidy server and its extensions

> Iris gives Mopidy a React and Redux web interface, pulls metadata and artwork from LastFM, lyrics from Genius and discovery from Spotify, and can stream the audio into the browser through Snapcast. It is a Python extension with a JavaScript front end, and the two halves are built by two different toolchains.

**jaedb/Iris** — Discover, explore and manage your music library across multiple sources with this beautiful web-based interface. Iris is a Mopidy frontend extension.

- Repository: https://github.com/jaedb/Iris
- Stars: 1,240 · Forks: 153
- Language: JavaScript
- License: Apache-2.0
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/jaedb-iris

## The server is the product, the interface is the extension

Iris is an extension for the Mopidy music server, and the readme says the aim is to bring all your music into one user-friendly and unified web-based interface that works beautifully, no matter your device.

The Mopidy model is the key to understanding it. Mopidy is a music server that exposes a common interface over a set of extensions, one per source, so a library can be served from a local folder, from Spotify or from something else, and every client sees the same API. Iris is a client in that sense: it is a web interface over the Mopidy HTTP API, plus the web extensions Mopidy can serve.

The integrations are the extensions Iris leans on. Spotify provides discovery of new, popular and related music. LastFM provides rich music metadata and artwork. Genius provides lyrics. Snapcast streams audio to multiple devices, and is what makes the streaming controls work, including the ability to play audio from the browser.

So the value is unification. A Mopidy install with a local library and a Spotify account is a genuinely large collection, and Iris is the interface that makes it browsable as one thing rather than as two.

The project is built and maintained by James Barnsley, the licence is recorded as Apache-2.0, and the last push was on 2026-08-04.

## What the interface actually does

The feature list is short, and each entry is a section of the interface.

Full web-based interface controls for Mopidy, which is the base capability. Browse and manage your playlists and tracks, which is the part that makes it usable as a daily player rather than a browser. Improved support for local libraries, powered by Mopidy-Local, which is an explicit dependency on the local extension doing the heavy lifting for your own files. Discover new, popular and related music, powered by Spotify, which is the extension into the streaming catalogue.

Two entries are about the browser rather than about the music. Streaming controls with the ability to play audio from your browser requires Snapcast, so the audio path in the browser depends on a separate service that is not part of Mopidy at all. And multiple language support, with the wiki linking a contributing page for translations.

The Snapcast dependency is worth pausing on, because it changes the deployment. Mopidy normally controls playback on the server, on a speaker connected to it. With Snapcast, the audio is synchronised across a set of devices, and Iris can play it in the browser tab. That is a good feature for a house with several rooms, and it is a second system to install and configure.

The screenshot in the readme is the main image of the interface, and the repository keeps a Screenshots/ directory as well as a screenshot.jpg at the top level.

## The requirements are short, and two of them are optional

The Requirements section lists three things, and the distinction between required and recommended is doing work.

Mopidy itself is required, since Iris is an extension for it. Mopidy-Spotify is recommended, not required, and Mopidy-Local is recommended, not required.

That second part is the useful design decision here. A Mopidy install with neither extension still gets a working Iris, with whatever sources are configured, but the two features that the feature list highlights, discovery of new music powered by Spotify and improved support for local libraries powered by Mopidy-Local, are the ones that go away. The interface is not a Spotify client with a file browser bolted on, it is a Mopidy client that takes on extra depth when more extensions are present.

The Getting started section is a set of wiki links rather than instructions, which is the usual shape for a project with a single maintainer and a large user base. There is an installation page, a debugging page under Advanced, a support page with a before you log an issue section, and a link to the changelog in the releases.

The repository also carries a Dockerfile and a Dockerfile.alpine, a docker/ directory and a docker-compose.example.yml, so a containerised install is possible alongside the usual Python package route, and there is a .htaccess at the top level, which is what a web interface served from a conventional web server needs.

## A React and Redux front end built with webpack

The package manifest describes the front end, and the dependency list is the clearest statement of the stack.

```json
"dependencies": {
  "react": "18.2.0",
  "react-dom": "18.2.0",
  "react-redux": "8.0.2",
  "redux": "4.2.0",
  "redux-thunk": "2.4.1",
  "reselect": "4.1.6",
  "sanitize-html": "2.7.0"
}
```

So it is React with Redux, react-router for navigation, thunk for asynchronous actions and reselect for memoised selectors, with redux-persist for persisting the store, probably so the interface remembers your preferences and your last view.

Three entries are worth calling out. sanitize-html is in the runtime dependencies, which tells you the interface renders HTML that comes from somewhere else, and Mopidy metadata and lyrics from Genius are exactly that, so the sanitisation is load bearing rather than decorative. react-dnd comes with both an HTML5 backend and a touch backend, so the interface supports drag and drop of tracks and playlists on a desktop and on a phone. And react-hotkeys-hook is there for keyboard control, which is a reasonable thing for a music player that is also a remote control.

The build is webpack with Babel, and the tests are Jest with a jest.config.js, a babel.config.js and a __tests__/ directory. The __mocks__/ directory sits next to it.

The analytics and monitoring dependencies are also visible: @sentry/browser, logrocket and react-ga, which is a set of choices worth a second look if you run a music server for a household rather than for yourself.

## The Docker image builds a Rust GStreamer plugin

The Dockerfile is where this project stops being a web interface, and the reason is a Spotify problem.

The first stage is a Rust base image used as a builder. It installs the GStreamer development packages, among them libgstreamer-plugins-base1.0-dev, libgstreamer1.0-dev, libcsound64-dev, libclang-14-dev, libpango1.0-dev, libdav1d-dev and libgtk-4-dev, and then clones a gst-plugins-rs repository and builds a single package from it.

```dockerfile
FROM docker.io/rust:slim-bookworm AS Builder
WORKDIR /usr/src/gst-plugins-rs
```

The package it builds is gst-plugin-spotify, and it installs the resulting shared objects into the GStreamer plugins directory of the target system. The plugin is compiled with --no-default-features, and the image handles several target architectures, with the build printing the target platform, architecture and variant as it goes.

Building the plugin in the image means the compiled shared objects are installed into the GStreamer plugins directory inside the container rather than taken from the host.

The release stage is a Debian bookworm slim image, so the final image is a Python and Mopidy install with the compiled plugin inside it. The Dockerfile.alpine variant exists for smaller images.

## The Python packaging side, and a mismatch in the licence

The Python side of the extension is packaged in the usual way, with a setup.py that is nothing but a call to setup, which means all the metadata is in setup.cfg, and a pyproject.toml that only declares the build system.

```python
from setuptools import setup

setup()
```

The pyproject file is mostly configuration for the tooling rather than for the package. Black is configured for the py37 and py38 targets with a line length of 80, and isort is configured with a multi-line output style, a trailing comma, use of parentheses, a line length of 88, and a sections list that puts the __tests__ directory in its own section ahead of the local folder.

That is a small file that says a lot about the project. The line lengths differ between the two tools, which is the usual way of keeping a formatter from fighting a linter, and the test section is declared explicitly so that import blocks in tests sort differently from import blocks in the source.

The rest of the tree supports the two toolchains. There is a mopidy_iris/ directory for the Python package, a src/ directory for the JavaScript, build_tools/ for the build scripts, a tox.ini for the test environments, a MANIFEST.in for the source distribution, an .nvmrc pinning the Node version, a .eslintrc.json and a .jshintrc, and an IRIS_VERSION file next to a VERSION file.

The licence is where the two halves disagree. The repository records Apache-2.0, and the package.json for the front end declares ISC. That is not a rounding error, and it is the kind of thing to settle with the maintainer before you redistribute the built assets.

## A release cadence that has slowed down

The release list is short and the gaps are long.

Version 3.70.0 was published on 2025-05-03, 3.69.3 on 2024-01-02 and 3.69.2 on 2023-10-24. So the recent history is one release in 2023, one in early 2024, one in May 2025, and a gap of about sixteen months between the last two.

The last push to the repository was on 2026-08-04, so the code is being worked on even though the last tagged release is from more than a year earlier. That pattern, active commits with infrequent tags, is typical of a project maintained in the gaps around other work.

What the delay means in practice depends on what you depend on. The interface talks to Mopidy over its HTTP API and to a handful of third party APIs, and those APIs change. A front end that has not been released for a year can develop exactly the mismatch you would expect, a layout that has moved on from the extension it is talking to, and the answer to that is usually to run the current master rather than the last tag.

The Mopidy extension ecosystem moves slowly, which is part of why a stable interface can last. The dependencies in the manifest are pinned to exact versions, React at 18.2.0 and React DOM at 18.2.0 among them, so a rebuild of the front end does not silently change the framework version underneath it.

## Conclusion

Adopt Iris when you already run Mopidy and want a browser interface that covers the whole library rather than just the local files, and you are willing to maintain an extension whose front end is a separate JavaScript build. Do not adopt it if you have no Mopidy server, since the extension has nothing to extend, and be careful about the browser streaming feature, which needs Snapcast as a separate service. Verify first which of the optional Mopidy extensions you have installed, since Spotify and Local are recommended but not required and the interface changes shape without them, and check the licence, because the repository records Apache-2.0 while the npm package manifest declares ISC.

## FAQ

### What is Iris?

Iris is an extension for the Mopidy music server that provides a web-based interface, so you can browse and manage your playlists and tracks and control playback from any device. It is built and maintained by James Barnsley.

### What does Iris need to work?

Mopidy is required. Mopidy-Spotify and Mopidy-Local are recommended but not required, and they are what provide the discovery of new, popular and related music and the improved support for local libraries.

### Which services does Iris integrate with?

Spotify for discovery, LastFM for rich music metadata and artwork, Genius for lyrics, and Snapcast to stream audio to multiple devices. The ability to play audio in the browser specifically requires Snapcast.

### How is the Iris front end built?

With React and Redux, using react-router, redux-thunk, reselect and redux-persist, and sanitising rendered HTML with sanitize-html. The bundle is produced by webpack with Babel, and the tests run under Jest.

### Why does the Iris Dockerfile build a Rust project?

The image builds the gst-plugin-spotify package from a gst-plugins-rs repository against the GStreamer development libraries, so the container ships a working Spotify plugin for a headless Mopidy install rather than depending on one from the host.

### Can I play music in the browser with Iris?

Yes, with Snapcast. The feature list describes streaming controls with the ability to play audio from your browser, and states that it requires Snapcast, so you need that service running alongside Mopidy.

## Sources

- [Issues](https://github.com/jaedb/Iris/issues)
- [jaedb/Iris on GitHub](https://github.com/jaedb/Iris)
- [License: Apache-2.0](https://github.com/jaedb/Iris/blob/master/LICENSE)
- [README](https://github.com/jaedb/Iris/blob/master/README.md)
- [Releases](https://github.com/jaedb/Iris/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/jaedb-iris
