Let’s be honest: if you’re running Navidrome, you’ve already opted out of Spotify’s data-harvesting circus. You care about your music, your metadata, and your privacy. But you also secretly miss that dopamine hit of Spotify Wrapped—the glittery, stats-heavy, “wow, I did listen to 47 hours of post-punk in March” moment. Enter Rewind: a tiny, self-hosted, HTML-only, zero-JS (yes, really) dashboard that turns your Navidrome library and play history into a personal, static, beautifully minimalist year-in-review. It’s not flashy. It doesn’t stream. It doesn’t even talk to your database—it parses Navidrome’s exported playlog.csv and library.json files and builds a snapshot. And it has 55 GitHub stars (as of June 2024), which tells you something: this niche is hungry for lightweight, privacy-respecting alternatives to commercial analytics.

What Is Rewind—and Why Does It Feel Like a Breath of Fresh Air?

Rewind is a static site generator—not a web app, not a service, not a daemon. It’s a single HTML file (plus a tiny style.css) that renders your listening stats client-side, using plain DOM manipulation and <template> tags. No frameworks. No tracking. No external fonts or CDNs. You feed it two files from Navidrome (more on that below), run a CLI command, and it spits out index.html. That’s it.

I’ve been running it for three weeks—generating monthly snapshots—and it’s the most satisfying self-hosted music tool I’ve added this year. Why? Because it’s honest. It doesn’t pretend to be real-time. It doesn’t need Redis or Postgres. It doesn’t phone home. And most importantly: it works on a Raspberry Pi 4 with 2GB RAM while Navidrome chugs along in the background.

Unlike Last.fm scrobblers (which require API keys, network calls, and trusting a third party), Rewind reads your local play logs. Unlike Spotisync or spotify-stats, it doesn’t depend on Spotify’s API or OAuth tokens—and it’s built for Navidrome, not grafted on as an afterthought.

That said: Rewind isn’t a replacement for a full analytics dashboard. It won’t show you skip rates, device breakdowns, or hour-of-day heatmaps. It’s a summary. A keepsake. A “here’s what you actually listened to, in your own library, on your own terms.”

How to Install and Generate Your First Rewind Report

Rewind is a Go binary with zero dependencies. The binary is ~4MB, statically linked, and runs on Linux, macOS, and Windows. At time of writing, the latest release is v0.3.1, tagged on GitHub.

First, grab the binary. For Linux x86_64 (the most common self-hosting setup):

curl -L https://github.com/BernardoGiordano/rewind/releases/download/v0.3.1/rewind-linux-amd64 -o /usr/local/bin/rewind
chmod +x /usr/local/bin/rewind

Verify it works:

rewind --help
# Output: "rewind v0.3.1 — generate a Spotify Wrapped-style report for Navidrome"

Now, you’ll need two Navidrome exports:

  • playlog.csv: Enable playlog in Navidrome config (playlog: true) and restart. Navidrome writes this to its data directory (e.g. /var/lib/navidrome/playlog.csv). Important: it appends — so if you want monthly/yearly snapshots, back it up first or truncate it before export.

  • library.json: Run navidrome export library --format json > library.json. This is a one-time export of your full catalog (artists, albums, tracks, durations, etc.). It’s ~10–50MB depending on library size (mine: 12,437 tracks → 28MB JSON).

Put both files in the same directory, then run:

rewind --playlog playlog.csv --library library.json --output ./rewind-report

That generates a self-contained ./rewind-report/index.html. Open it in any browser—no server needed.

I run this weekly via cron, using a simple wrapper script that auto-backs up playlog.csv, regenerates library.json, and rsyncs the result to my static web root:

#!/bin/bash
# /opt/rewind/generate.sh
set -e
NAVIDROME_DATA="/var/lib/navidrome"
REPO_DIR="/opt/rewind"
OUTPUT_DIR="/var/www/rewind"

cp "$NAVIDROME_DATA/playlog.csv" "$REPO_DIR/playlog.csv.bak"
navidrome export library --format json > "$REPO_DIR/library.json"
rewind --playlog "$REPO_DIR/playlog.csv" --library "$REPO_DIR/library.json" --output "$OUTPUT_DIR"

Then in crontab (sudo crontab -e):

# Every Sunday at 3am
0 3 * * 0 /opt/rewind/generate.sh

Running Rewind with Docker (Yes, It’s Possible—Even If It’s Overkill)

Rewind doesn’t need Docker. But if you’re managing everything via docker-compose.yml, you’ll want it containerized. Here’s how I do it—using multi-stage build to keep the image tiny (under 15MB):

# docker-compose.yml
version: '3.8'
services:
  rewind:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - /var/lib/navidrome:/data:ro
      - /var/www/rewind:/output
    command: >
      --playlog /data/playlog.csv
      --library /data/library.json
      --output /output
    restart: "no"

And Dockerfile:

# syntax=docker/dockerfile:1
FROM golang:1.22-alpine AS builder
RUN apk add --no-cache git
WORKDIR /src
RUN git clone https://github.com/BernardoGiordano/rewind .
RUN go build -o /bin/rewind .

FROM alpine:3.19
COPY --from=builder /bin/rewind /usr/local/bin/rewind
ENTRYPOINT ["rewind"]

Build and run once:

docker compose build
docker compose run --rm rewind

Note: restart: "no" is intentional. Rewind is a one-shot generator—not a service. You don’t want it running 24/7. Run it on schedule (via docker compose run in cron) or trigger it from Navidrome’s --playlog-cmd hook (advanced, but possible).

Why Self-Host Rewind? Who Is This Actually For?

Let’s cut through the hype. Rewind isn’t for everyone.

It’s for:

  • Navidrome purists who’ve already rejected Spotify, Plex Music, and even Funkwhale for its complexity.
  • Sysadmins who hate moving parts: no database, no sessions, no background workers, no API keys.
  • People with slow or metered connections: the entire report is <500KB HTML+CSS—even with 15K tracks.
  • Those archiving listening habits long-term: since it only reads static files, you can generate reports for past years, as long as you kept old playlog.csv backups.

It’s not for:

  • Users wanting live stats or dashboards (try Navidrome’s built-in stats page instead).
  • People who want artist images or album art embedded (Rewind uses placeholders only—it doesn’t fetch or store cover art).
  • Anyone needing multi-user support (it’s single-user, single-library only).

Hardware-wise? I ran it on a Raspberry Pi 4 (2GB RAM, microSD) with Navidrome, Jellyfin, and Pi-hole all active. rewind itself peaks at ~12MB RAM and 0.1s CPU time, even on a 28MB library.json. On an Intel N5105 mini-PC, it finishes in ~80ms. It’s stupidly lightweight.

Rewind vs. Alternatives: Where It Fits in the Ecosystem

If you’re already using Last.fm + LastExport, you get richer graphs and timeline views—but you’re trusting Last.fm with your full listening history, and you’re locked into their API rate limits and UI. Rewind gives you raw numbers, zero abstraction, and full ownership.

If you’ve tried Spotisync or spotify-stats, you’ll notice Rewind feels slower to set up (requires manual exports), but faster to trust. No OAuth dance. No “Allow Spotisync to read your private playlists”.

What about Navidrome’s built-in /stats page? It’s great for real-time top tracks—but it’s not exportable, not shareable, and doesn’t break down by year/month. Rewind fills that gap without touching Navidrome’s internals.

And no, it’s not a competitor to ListenBrainz, which is a full open-source scrobbling platform with federation and ML-backed recommendations. Rewind is smaller than ListenBrainz’s logo file.

Here’s the TL;DR comparison:

Tool Navidrome-native? Static export? Requires API key? Runs on Pi 4? Tracks library size
Rewind ✅ Yes ✅ Yes ❌ No ✅ Yes (<15MB RAM) ~12K–25K tracks tested
Last.fm + LastExport ❌ No ✅ Yes ✅ Yes ✅ Yes Limited by Last.fm API
Navidrome /stats ✅ Yes ❌ No ❌ No ✅ Yes Real-time only
ListenBrainz ❌ No (scrobbles only) ✅ Yes (via API) ✅ Yes ❌ Heavy (needs Postgres + Redis) Unlimited, but complex

The Verdict: Is Rewind Worth Deploying?

Yes—but with caveats.

I’ve deployed Rewind on three different setups: a homelab NUC (Intel i3), a Raspberry Pi 4, and a $5/month Hetzner Cloud instance. It works identically on all three. The HTML output is crisp, responsive, and actually fun to scroll through. Seeing “Top Genre: Jazz Fusion (142 plays)” or “Most Played Day: Saturday (23% of plays)” feels oddly validating.

Rough edges? A few:

  • No automatic library updates: You must re-run navidrome export library if you add/remove albums. I do this monthly. Not a dealbreaker—but it’s manual.
  • No search or filtering: It’s a static report. You can’t click “show only 2023” unless you generated a separate playlog-2023.csv.
  • Timezone handling is basic: It parses timestamps as-is from playlog.csv (which uses Navidrome’s local time). If your server’s TZ is wrong, your “Most Played Hour” will be off.
  • No mobile menu collapse: On small screens, the sidebar stays open and pushes content right. An easy CSS fix, but not included yet.

Also: it only supports one language—English. The author has said i18n isn’t planned, since the goal is minimalism, not feature bloat.

That said—the fact that it’s a single-file Go binary, written by one person (Bernardo Giordano, also behind the excellent Doom Emacs config), and has zero dependencies, makes it deeply trustworthy. It’s the kind of tool that’ll still work in 2030, long after your Docker registry credentials have expired and your Node.js version is deprecated.

Final Thoughts: A Tool That Respects Your Time and Data

Rewind isn’t trying to replace anything. It’s not “the next big thing.” It’s a quiet, well-crafted tool for people who believe music stats should be yours, not a SaaS KPI.

It won’t make your Navidrome instance faster. It won’t sync with your headphones. It won’t send notifications. But every time I open my /rewind URL and see “You listened to 197 hours of music this quarter”—and know that number came only from files on my own disk—I feel something rare in self-hosting: calm.

So yes—deploy it. Run it monthly. Tuck the HTML into your /var/www or Netlify or even a USB stick. And when Spotify Wrapped drops next December, smile, open your local index.html, and remember: you didn’t trade privacy for poetry. You built your own.