Spotify, native and fast. One lightweight Rust app for your whole library, local playback, and Spotify Connect on Linux, macOS, and Windows.
3,777
stars
184
commits
Rust
primary language
Sep 9, 2026
updated
Spotify, native and fast. A lightweight Spotify client written in Rust with egui, playing music through librespot. It runs on Linux, macOS, and Windows, starts in well under a second, and stays small while it runs. There is no browser engine anywhere in the process.
Playing needs Spotify Premium. Spotify only lets Premium accounts play music through another app, on the computer itself or on any other device. With a Free account Fastpotify can browse the library but not play it, and says so at sign-in.
Fastpotify follows in the footsteps of Omarchy Spotify and spotify-tui: the familiar Spotify layout, access to your library, and a Spotify Connect receiver in one desktop application rather than a shell plugin.

Documentation: fastpotify.rocks: what it is, getting started, everyday use, and how it connects to Spotify.
Ctrl+M turns the window into a tiny player that
wears classic .wsz skins, drawn pixel for pixel at 1x to 4x, with the
spectrum analyser, the playlist, and the equalizer hanging under it as
they did; the logo in the skin brings the big window back. Drop a skin
from the Winamp Skin Museum on either window
to add it.Ctrl+/ or ? lists
them).Ctrl+Q; turn the behaviour off in
Settings if you prefer close-to-quit. On macOS the Dock icon stays present,
and clicking it opens the window again.playerctl see Fastpotify like any other player. On macOS and Windows,
fastpotify next and its siblings drive the running app from a terminal,
a launcher, or a hotkey.On Arch Linux, Fastpotify is in the AUR:
yay -S fastpotify # the released build
yay -S fastpotify-git # built from the latest commit
On macOS, with Homebrew:
brew install --cask crmne/tap/fastpotify
Everywhere else it is a single binary. Build it with a stable Rust toolchain (1.95 or newer):
cargo install --path .
On Linux you also need the development packages for ALSA, PulseAudio (which covers PipeWire), and the usual windowing libraries, for example on Arch:
sudo pacman -S --needed alsa-lib libpulse libxkbcommon wayland
and on Debian or Ubuntu:
sudo apt install libasound2-dev libpulse-dev libxkbcommon-dev libwayland-dev
With Nix, nix develop provides all of it, along with
the exact toolchain rust-toolchain.toml pins.
Titles in a script the interface font does not cover -- Chinese, Japanese,
Korean, Arabic, Hebrew, Thai, the Indic scripts and a dozen more -- are drawn
with a face borrowed from the system rather than bundled, which would cost
more than ten megabytes for Chinese alone. macOS and Windows carry faces for
the common ones; on Linux install the Noto families for the scripts you
listen to, for example noto-fonts and noto-fonts-cjk (Arch) or
fonts-noto and fonts-noto-cjk (Debian or Ubuntu). A script with no face
installed still shows as empty boxes.
A desktop entry is provided in packaging/applications/fastpotify.desktop.
Press Sign in with Spotify. Your browser opens Spotify's own consent
page (Authorization Code with PKCE); Fastpotify never sees your password.
When Spotify redirects back to the app, your library, search, and control
of other devices work immediately. The refresh token is stored in the
platform's state directory (~/.local/state/fastpotify on Linux), so the
browser is needed once per machine.
Playing music on this computer is one more one-time browser approval. Spotify treats streaming as a separate grant for its own client identity, which is what librespot plays with. Take it from the device menu ("Play here, set up once") or Settings; it needs Spotify Premium, and librespot stores a reusable credential for later sessions. Browsing works on any account without this step; playing, here or on another device, does not, because Spotify's API only takes playback commands from Premium accounts.
The Web API always keeps shared catalog coverage. You can also register a personal Spotify Development Mode app and paste its Client ID in Settings → Account; supported requests use its separate quota while complete playlist views, playlist-bearing search, external playlists, and unavailable operations continue through the shared app.
We are not aware of a Spotify account being suspended for using Fastpotify or another librespot player with Premium. Sign-in happens on Spotify's own pages, audio uses the quality included with Premium, DRM stays intact, and Fastpotify does not rip tracks or block ads.
Reported suspensions usually involve modded apps that remove ads from free accounts, track ripping, or stream manipulation. Fastpotify does none of those things, and CONTRIBUTING.md prohibits them.
| Shortcut | What it does |
|---|---|
Space | Play or pause |
Ctrl+← / Ctrl+→ | Previous or next |
Shift+← / Shift+→ | Seek 10 seconds |
Ctrl+↑ / Ctrl+↓ | Volume |
M | Mute |
S / R | Shuffle / cycle repeat |
Q | Queue panel |
Ctrl+F or / | Search |
Ctrl+B | Show or hide the sidebar |
Alt+← / Alt+→ | Back or forward |
Ctrl+H / Ctrl+L | Home / Liked Songs |
Ctrl+Shift+A / Ctrl+Shift+B | Playing artist / album |
Ctrl+M | Winamp mini player |
Ctrl+, | Settings |
Ctrl+/ or ? | All shortcuts |
Ctrl+Q | Quit |
On macOS, Cmd replaces Ctrl.
On Linux, Fastpotify is an MPRIS player, so playerctl --player=fastpotify play-pause already works.
macOS and Windows have no such bus, so the same verbs are subcommands. They talk to the instance already running and print nothing on success:
fastpotify play-pause fastpotify volume 40
fastpotify play fastpotify volume-up [percent]
fastpotify pause fastpotify volume-down [percent]
fastpotify next fastpotify mute
fastpotify previous fastpotify shuffle [on|off]
fastpotify seek 15 fastpotify repeat [off|context|track]
fastpotify seek -- -15 fastpotify like
fastpotify seek-to 90 fastpotify play-uri spotify:playlist:37i9…
fastpotify show fastpotify transfer <device-id>
fastpotify now-playing [--raw] fastpotify devices [--raw]
shuffle and repeat toggle when asked for nothing in particular and set
the state outright when given one, which is what a button that draws the
current state wants: a missed update otherwise leaves the two disagreeing
until the next press. like saves the playing track to your library, or
takes it back out.
now-playing prints one readable line; --raw prints the fields
tab-separated (state, title, artists, album, position_ms, duration_ms,
volume, shuffle, repeat, art_url, saved, device) for a script that wants
one of them. saved is yes, no, or unknown while the answer is still
on its way. The last three fields were added after the first nine, and
appended rather than woven in, so a script written against the older shape
still reads correctly.
devices lists the Spotify Connect devices, id first, the active one
marked with *; --raw prints them as JSON. The app only refreshes that
list while its own picker is open, so asking for it also asks it to look
again: on a cold list the first call can come back empty and the next one
has it.
A verb exits non-zero when Fastpotify is not running.
Launchers such as Raycast or Alfred can use these commands to control playback. The Stream Deck plugin speaks the same channel, which is why the verbs cover more than a media key can ask for.
Settings live in one readable JSON file (~/.config/fastpotify/settings.json
on Linux). They include the Connect device name, bitrate, normalisation,
autoplay, gapless playback, the audio backend (PulseAudio/PipeWire or ALSA on
Linux), audio cache size, theme, sidebar state, whether pages take colour
from artwork, and the mini player's skin and size.
Playback settings apply when you press Apply and restart playback.
Caches (audio, artwork) live under the cache directory and can be deleted at any time without signing you out.
src/player.rs: the librespot session, player, mixer, and Spirc (Spotify
Connect) wrapped into one engine that folds player events into a state
snapshot for the interface.src/api/: one routing gateway over independent shared and personal Web API
sessions, each with bounded concurrency and coordinated Retry-After
handling. Capability profiles select current endpoint contracts before a
request is dispatched.src/backend.rs: a tokio runtime on its own thread; the interface talks to
it through channels and is woken with request_repaint, so the app is idle
when nothing happens.src/images.rs: album art as an egui bytes loader with a disk cache and
time-based eviction, plus the accent-colour extraction.src/app.rs, src/model.rs, src/ui/: state, navigation, and the views.
Views collect Actions while drawing and the app applies them afterwards.src/mpris.rs: Linux media controls on a dedicated thread.Fastpotify pins its Rust toolchain in rust-toolchain.toml; cargo test
covers the API models, dual-session routing, PKCE, the player state machine,
and a headless render of every page, panel, and dialog.
To look at the interface without a Spotify account, build with the demo
feature and start it with sample data:
cargo run --features demo -- --demo --demo-page playlist:pl1 --demo-show queue
Demo mode never writes settings. --demo-shot <PATH> writes the window to a
PNG and exits, which is how the screenshot above is made.
Read CONTRIBUTING.md before opening an issue or pull request. It describes the project's design principles, product boundaries, and the complete local checks that every change must pass.
Fastpotify stands on librespot, egui, the Inter typeface (OFL), and Lucide icons (ISC).
Fastpotify is an independent project and is not affiliated with Spotify. Spotify is a trademark of Spotify AB.
Licensed under the MIT License.
Rust
99.3%
Spotify, native and fast. One lightweight Rust app for your whole library, local playback, and Spotify Connect on Linux, macOS, and Windows.
3,777
stars
184
commits
Rust
primary language
Sep 9, 2026
updated
Spotify, native and fast. A lightweight Spotify client written in Rust with egui, playing music through librespot. It runs on Linux, macOS, and Windows, starts in well under a second, and stays small while it runs. There is no browser engine anywhere in the process.
Playing needs Spotify Premium. Spotify only lets Premium accounts play music through another app, on the computer itself or on any other device. With a Free account Fastpotify can browse the library but not play it, and says so at sign-in.
Fastpotify follows in the footsteps of Omarchy Spotify and spotify-tui: the familiar Spotify layout, access to your library, and a Spotify Connect receiver in one desktop application rather than a shell plugin.

Documentation: fastpotify.rocks: what it is, getting started, everyday use, and how it connects to Spotify.
Ctrl+M turns the window into a tiny player that
wears classic .wsz skins, drawn pixel for pixel at 1x to 4x, with the
spectrum analyser, the playlist, and the equalizer hanging under it as
they did; the logo in the skin brings the big window back. Drop a skin
from the Winamp Skin Museum on either window
to add it.Ctrl+/ or ? lists
them).Ctrl+Q; turn the behaviour off in
Settings if you prefer close-to-quit. On macOS the Dock icon stays present,
and clicking it opens the window again.playerctl see Fastpotify like any other player. On macOS and Windows,
fastpotify next and its siblings drive the running app from a terminal,
a launcher, or a hotkey.On Arch Linux, Fastpotify is in the AUR:
yay -S fastpotify # the released build
yay -S fastpotify-git # built from the latest commit
On macOS, with Homebrew:
brew install --cask crmne/tap/fastpotify
Everywhere else it is a single binary. Build it with a stable Rust toolchain (1.95 or newer):
cargo install --path .
On Linux you also need the development packages for ALSA, PulseAudio (which covers PipeWire), and the usual windowing libraries, for example on Arch:
sudo pacman -S --needed alsa-lib libpulse libxkbcommon wayland
and on Debian or Ubuntu:
sudo apt install libasound2-dev libpulse-dev libxkbcommon-dev libwayland-dev
With Nix, nix develop provides all of it, along with
the exact toolchain rust-toolchain.toml pins.
Titles in a script the interface font does not cover -- Chinese, Japanese,
Korean, Arabic, Hebrew, Thai, the Indic scripts and a dozen more -- are drawn
with a face borrowed from the system rather than bundled, which would cost
more than ten megabytes for Chinese alone. macOS and Windows carry faces for
the common ones; on Linux install the Noto families for the scripts you
listen to, for example noto-fonts and noto-fonts-cjk (Arch) or
fonts-noto and fonts-noto-cjk (Debian or Ubuntu). A script with no face
installed still shows as empty boxes.
A desktop entry is provided in packaging/applications/fastpotify.desktop.
Press Sign in with Spotify. Your browser opens Spotify's own consent
page (Authorization Code with PKCE); Fastpotify never sees your password.
When Spotify redirects back to the app, your library, search, and control
of other devices work immediately. The refresh token is stored in the
platform's state directory (~/.local/state/fastpotify on Linux), so the
browser is needed once per machine.
Playing music on this computer is one more one-time browser approval. Spotify treats streaming as a separate grant for its own client identity, which is what librespot plays with. Take it from the device menu ("Play here, set up once") or Settings; it needs Spotify Premium, and librespot stores a reusable credential for later sessions. Browsing works on any account without this step; playing, here or on another device, does not, because Spotify's API only takes playback commands from Premium accounts.
The Web API always keeps shared catalog coverage. You can also register a personal Spotify Development Mode app and paste its Client ID in Settings → Account; supported requests use its separate quota while complete playlist views, playlist-bearing search, external playlists, and unavailable operations continue through the shared app.
We are not aware of a Spotify account being suspended for using Fastpotify or another librespot player with Premium. Sign-in happens on Spotify's own pages, audio uses the quality included with Premium, DRM stays intact, and Fastpotify does not rip tracks or block ads.
Reported suspensions usually involve modded apps that remove ads from free accounts, track ripping, or stream manipulation. Fastpotify does none of those things, and CONTRIBUTING.md prohibits them.
| Shortcut | What it does |
|---|---|
Space | Play or pause |
Ctrl+← / Ctrl+→ | Previous or next |
Shift+← / Shift+→ | Seek 10 seconds |
Ctrl+↑ / Ctrl+↓ | Volume |
M | Mute |
S / R | Shuffle / cycle repeat |
Q | Queue panel |
Ctrl+F or / | Search |
Ctrl+B | Show or hide the sidebar |
Alt+← / Alt+→ | Back or forward |
Ctrl+H / Ctrl+L | Home / Liked Songs |
Ctrl+Shift+A / Ctrl+Shift+B | Playing artist / album |
Ctrl+M | Winamp mini player |
Ctrl+, | Settings |
Ctrl+/ or ? | All shortcuts |
Ctrl+Q | Quit |
On macOS, Cmd replaces Ctrl.
On Linux, Fastpotify is an MPRIS player, so playerctl --player=fastpotify play-pause already works.
macOS and Windows have no such bus, so the same verbs are subcommands. They talk to the instance already running and print nothing on success:
fastpotify play-pause fastpotify volume 40
fastpotify play fastpotify volume-up [percent]
fastpotify pause fastpotify volume-down [percent]
fastpotify next fastpotify mute
fastpotify previous fastpotify shuffle [on|off]
fastpotify seek 15 fastpotify repeat [off|context|track]
fastpotify seek -- -15 fastpotify like
fastpotify seek-to 90 fastpotify play-uri spotify:playlist:37i9…
fastpotify show fastpotify transfer <device-id>
fastpotify now-playing [--raw] fastpotify devices [--raw]
shuffle and repeat toggle when asked for nothing in particular and set
the state outright when given one, which is what a button that draws the
current state wants: a missed update otherwise leaves the two disagreeing
until the next press. like saves the playing track to your library, or
takes it back out.
now-playing prints one readable line; --raw prints the fields
tab-separated (state, title, artists, album, position_ms, duration_ms,
volume, shuffle, repeat, art_url, saved, device) for a script that wants
one of them. saved is yes, no, or unknown while the answer is still
on its way. The last three fields were added after the first nine, and
appended rather than woven in, so a script written against the older shape
still reads correctly.
devices lists the Spotify Connect devices, id first, the active one
marked with *; --raw prints them as JSON. The app only refreshes that
list while its own picker is open, so asking for it also asks it to look
again: on a cold list the first call can come back empty and the next one
has it.
A verb exits non-zero when Fastpotify is not running.
Launchers such as Raycast or Alfred can use these commands to control playback. The Stream Deck plugin speaks the same channel, which is why the verbs cover more than a media key can ask for.
Settings live in one readable JSON file (~/.config/fastpotify/settings.json
on Linux). They include the Connect device name, bitrate, normalisation,
autoplay, gapless playback, the audio backend (PulseAudio/PipeWire or ALSA on
Linux), audio cache size, theme, sidebar state, whether pages take colour
from artwork, and the mini player's skin and size.
Playback settings apply when you press Apply and restart playback.
Caches (audio, artwork) live under the cache directory and can be deleted at any time without signing you out.
src/player.rs: the librespot session, player, mixer, and Spirc (Spotify
Connect) wrapped into one engine that folds player events into a state
snapshot for the interface.src/api/: one routing gateway over independent shared and personal Web API
sessions, each with bounded concurrency and coordinated Retry-After
handling. Capability profiles select current endpoint contracts before a
request is dispatched.src/backend.rs: a tokio runtime on its own thread; the interface talks to
it through channels and is woken with request_repaint, so the app is idle
when nothing happens.src/images.rs: album art as an egui bytes loader with a disk cache and
time-based eviction, plus the accent-colour extraction.src/app.rs, src/model.rs, src/ui/: state, navigation, and the views.
Views collect Actions while drawing and the app applies them afterwards.src/mpris.rs: Linux media controls on a dedicated thread.Fastpotify pins its Rust toolchain in rust-toolchain.toml; cargo test
covers the API models, dual-session routing, PKCE, the player state machine,
and a headless render of every page, panel, and dialog.
To look at the interface without a Spotify account, build with the demo
feature and start it with sample data:
cargo run --features demo -- --demo --demo-page playlist:pl1 --demo-show queue
Demo mode never writes settings. --demo-shot <PATH> writes the window to a
PNG and exits, which is how the screenshot above is made.
Read CONTRIBUTING.md before opening an issue or pull request. It describes the project's design principles, product boundaries, and the complete local checks that every change must pass.
Fastpotify stands on librespot, egui, the Inter typeface (OFL), and Lucide icons (ISC).
Fastpotify is an independent project and is not affiliated with Spotify. Spotify is a trademark of Spotify AB.
Licensed under the MIT License.
Rust
99.3%