Artwork & Performance
Nokkvi uses a server-only artwork pipeline — images are fetched directly from Navidrome on demand and kept in an in-memory GPU texture cache. There is no local disk cache for browsing artwork. (The MPRIS integration writes a per-track mpris-art-<pid>-<cover_id>_<hash>.jpg (the previous one is removed on each song change, so it’s ~one file at a time, plus a mpris-art-<pid>-placeholder.jpg written once per process) to $XDG_CACHE_HOME/nokkvi/ so D-Bus clients can read the now-playing cover via file:// without leaking your Subsonic credential — those are the only standalone artwork files Nokkvi writes. Remembered radio-station art is also kept on disk, but as bytes inside Nokkvi’s local state database rather than a separate image file.)
How Artwork Works
Section titled “How Artwork Works”When an album comes into view, Nokkvi fetches the image directly from your Navidrome server and decodes it into a GPU texture handle. Two in-memory LRU caches keep recent images warm: a thumbnail cache holds up to 1024 slot-row thumbnails, and a panel cache holds up to 200 full-size images for the large artwork panel. Browsing a section of your library you visited recently has zero network overhead.
Thumbnails in list views are populated around the visible viewport — items well outside the visible area aren’t pre-loaded.
The large panel downloads one full-size cover at a time. When you scroll faster than covers arrive, Nokkvi skips the rows you pass and fetches the newest one as soon as the cover before it lands, showing that row’s thumbnail meanwhile. On a fast server every cover still arrives as you reach it; on a slow one this keeps the full-size covers of the rows you passed from holding up the thumbnails of the rows you stopped on.
On Navidrome 0.64+
Section titled “On Navidrome 0.64+”A 0.64 server describes each album, artist, and playlist cover alongside the row itself, which lets Nokkvi do four things it can’t on older servers:
- A thumbnail loads as a blurred preview. While the image is in flight, an album or artist row shows a blurred preview of its cover, decoded from the few bytes the server sends with the row (its ThumbHash). Song rows show it too when Nokkvi has already loaded the song’s album, for example in the Albums view. A row without a preview takes the cover’s dominant color instead of the flat
bg2square. A loaded cover goes back to thebg2backdrop, since square covers arrive padded with transparency and a tint would bleed into their letterbox bars. - The large panel never sits blank. Until a thumbnail or the full-size cover arrives, the panel shows the same blurred preview.
- Art the server says is missing is never requested. A cover Navidrome has settled doesn’t exist anywhere gets no URL at all, so Nokkvi shows its own empty square instead of fetching the server’s placeholder picture. An artist with no picture of its own on the server but a poster from an outside source (Deezer, Last.fm) is the one exception: its thumbnail is that poster, shrunk to thumbnail size, the same picture the large panel shows.
- A replaced cover appears on its own. Covers are versioned by the server’s image hash, which changes exactly when the image bytes do — not on a play-count bump. Scroll the row back into view (or center it) and the new cover is there, in both the thumbnail and the large panel.
Older servers still work: they version covers by the entity’s updated_at instead, show no preview or tint, and fall back to the manual Refresh Artwork.
The Artwork Panel
Section titled “The Artwork Panel”The large artwork panel sits alongside most library views — Albums, Songs, Queue, Artists, Genres, Playlists, Radios, and the Similar tab in the Library Browser (it also appears in the playlist editor). It shows the cover for whichever row is centered, falling back to a 3×3 collage in Genres or Playlists when the focused item spans multiple albums. On the Radios view it shows the station’s artwork.
A playlist’s own cover can be set or reset from the editor’s edit-bar thumbnail once the playlist has been saved.
Artwork sits beside the slot list. Used by always_native, always_stretched, and auto on wide windows.
The column runs the window’s full height. The top navigation bar, the metadata strip and the player bar sit beside it over the list only, and so do toasts and the bottom-band visualizer. The Library Browser’s split view keeps them full width.

Artwork stacks above the slot list. Used by always_vertical_native, always_vertical_stretched, and auto on tall windows.

How it sizes and whether it shows up is controlled by artwork_column_mode:
| Mode | Behavior |
|---|---|
auto (default) | Beside the slot list, the artwork is a square as tall as the window. Hides when the remaining slot-list width would drop below 800 px. On tall windows, artwork stacks vertically above the slot list instead — sized edge-to-edge to the window width (capped at 1000 px). Here artwork_auto_max_pct × window height acts as a threshold: the vertical panel only appears when that value is at least the window width (otherwise it would letterbox, so it stays hidden). It also hides when fewer than 400 px of height would remain below it. |
always_native | Always visible at a fixed fraction of window width. The image stays square and letterboxes vertically if the column is taller than wide. |
always_stretched | Always visible at a fixed fraction of window width. The image fills the column non-square per artwork_column_stretch_fit — cover crops to fit, fill distorts. |
always_vertical_native | Always visible; artwork stacked above the slot list at a fixed fraction of window height. The image stays square, letterboxed horizontally as needed. |
always_vertical_stretched | Always visible; artwork stacked above the slot list at a fixed fraction of window height. The image fills the rect per artwork_column_stretch_fit — cover crops, fill distorts. |
never | Column is always hidden. |
The always_* modes resize from the artwork’s edge that faces the slot list. Nothing is drawn there: hover a thin strip along that edge and the cursor turns into a resize arrow. In always_native and always_stretched that’s the artwork’s left edge — drag horizontally to resize; the new fraction is saved to artwork_column_width_pct (clamped to 0.05–0.80). In always_vertical_native and always_vertical_stretched it’s the artwork’s bottom edge — drag vertically to resize; the new fraction is saved to artwork_vertical_height_pct (clamped to 0.10–0.80). auto sizes itself, so it can’t be resized.
Artwork Quality
Section titled “Artwork Quality”The artwork_resolution setting controls the size requested for large panel artwork (the full-size view when an album is focused):
| Option | Requested Size |
|---|---|
default | 1000 px |
high | 1500 px |
ultra | 2000 px |
original | Full resolution |
Thumbnails in list views always request 80 px regardless of this setting.
In always_native, always_vertical_native, and auto stacked above the list, the panel never grows past 1000 px, so on a display at scale 1 default already fills it and the higher settings only cost bandwidth and server cache. They pay off in three cases:
- A scaled display. The 1000 px cap is in logical pixels, so at scale 1.5 the panel can be 1500 physical pixels wide (
high), and at scale 2, 2000 (ultra). autobeside the list. The square is as tall as the window, so on a window taller than 1000 pxhighorultrakeeps the cover sharp.- The stretched modes.
always_stretchedandalways_vertical_stretchedfill the full height or width of the window, and withcoverfit the image is scaled up to fill that.
original returns the file exactly as stored, without the square padding the other options get. In the square panel a non-square cover is therefore cropped to fill the square rather than shown whole.
Track Artwork
Section titled “Track Artwork”By default every song shows its album’s cover. If your files carry their own embedded art (singles collected into one album, compilations, a different picture per track), set Settings → General → Track Artwork to Track’s Own Cover, or track_artwork = "own_cover" in config.toml:
- Songs in the queue, the Songs view, playlists, Similar, Harbour and Trawl show the art embedded in their own file.
- The now-playing cover, the mini player, Theater Mode, the lyrics backdrop, the album-art accent and the MPRIS cover follow the playing song’s own art.
- A song with no art of its own keeps its album’s cover. Album, artist, genre and playlist covers don’t change.
Nokkvi asks Navidrome for each song’s own cover separately, so an album whose files all embed the same picture downloads it once per track instead of once per album. That’s why it’s off by default. If Navidrome’s EnableMediaFileCoverArt option is off, the server answers with the album’s cover for every song, so the setting changes nothing.
Navidrome Server Settings
Section titled “Navidrome Server Settings”Because Nokkvi keeps no disk cache for browsing artwork, your Navidrome server does the heavy lifting of serving and resizing artwork. Nokkvi asks for every cover as a padded square, and with default settings Navidrome encodes square artwork as lossless PNG, so what you see is already full quality. The settings below in navidrome.toml are all documented in Navidrome’s available options reference:
ImageCacheSize
Section titled “ImageCacheSize”Navidrome keeps each resized cover in an on-disk cache, keyed by image and size. A lossless PNG at the default 1000 px panel size is about a megabyte (up to ~3 MB for detailed covers), so the default 100MB holds fewer than a hundred panel covers; after that, the server decodes and resizes a cover again every time it’s evicted. Set it to at least 1500MB:
ImageCacheSize = "1500MB"UICoverArtSize (optional)
Section titled “UICoverArtSize (optional)”Navidrome’s artwork precache (on by default) resizes each cover ahead of time at UICoverArtSize, the size its own web UI requests (default 300). Nokkvi never requests that size, so out of the box every cover is resized on first view. If you keep artwork_resolution at default, setting this to 1000 makes the precache produce exactly the panel image Nokkvi asks for:
UICoverArtSize = 1000The tradeoff is that Navidrome’s web UI then loads 1000 px covers too. The precache runs when Navidrome picks up a cover, so covers it already knows about stay cold until they’re first viewed. The setting accepts 200–1200, so it can’t match the high or ultra resolutions.
EnableWebPEncoding
Section titled “EnableWebPEncoding”Leave this at its default of false. Turning it on makes Navidrome encode every resized cover as WebP at CoverArtQuality (default 75), which replaces the lossless PNGs Nokkvi receives with lossy ones. The files get smaller, but covers lose detail.
CoverArtQuality itself has no effect on Nokkvi while EnableWebPEncoding is off, since PNG has no quality setting.
Updating Artwork
Section titled “Updating Artwork”If you update a cover in Navidrome and want Nokkvi to reflect the change, right-click the artwork panel in the Albums, Songs, or Queue view and select Refresh Artwork. This evicts the cached image and fetches the latest version from the server. On Navidrome 0.64+ you rarely need it — a replaced cover shows up by itself the next time the row comes into view.
Radio stations work differently — right-click a station in the Radios list and choose Refresh Artwork to forget its remembered stream art and re-capture it.