https://github.com/suitux/tagr
Self-hosted web app for browsing, playing, and editing music file metadata. Features a three-panel UI to navigate your library, listen to tracks, and write tag changes directly back to audio files. Built with Next.js, React, Prisma + SQLite, and node-taglib-sharp.
https://github.com/suitux/tagr
audio docker headless jellyfin metadata-management music music-player self-hosted tag
Last synced: 3 months ago
JSON representation
Self-hosted web app for browsing, playing, and editing music file metadata. Features a three-panel UI to navigate your library, listen to tracks, and write tag changes directly back to audio files. Built with Next.js, React, Prisma + SQLite, and node-taglib-sharp.
- Host: GitHub
- URL: https://github.com/suitux/tagr
- Owner: suitux
- Created: 2026-02-19T11:00:27.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-04-02T16:22:57.000Z (3 months ago)
- Last Synced: 2026-04-03T02:45:30.325Z (3 months ago)
- Topics: audio, docker, headless, jellyfin, metadata-management, music, music-player, self-hosted, tag
- Language: TypeScript
- Homepage: https://tagr-demo.fly.dev/
- Size: 7.93 MB
- Stars: 59
- Watchers: 2
- Forks: 1
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Funding: .github/funding.yml
Awesome Lists containing this project
README
Tagr
A self-hosted music metadata editor with a modern, intuitive web UI.
Live Demo — login with demo / demo
Hosted on Fly.io with auto-stop to save costs. First load may take ~30s while the machine wakes up.
Demo is read-only: you can browse, filter, scan, view song edit history, and play songs, but metadata editing is disabled.
Tagr lets you browse, edit, and manage audio file tags from any browser — desktop or mobile. Just point it at your music folders, and get a clean three-panel interface for organizing your library — no desktop apps, no CLI wizardry.

---
## Features
### Metadata Editing
- Edit **40+ metadata fields** inline — title, artist, album, year, genre, composer, BPM, lyrics, and more
- **Custom metadata** — add, edit, and remove your own custom tags beyond the standard fields
- **Album art** management — view, replace, and upload cover images directly
- **Star ratings** (1–5) with a visual widget
- Support for track/disc numbering, sort fields, catalog numbers, barcodes, and extended tags
- Read-only display of audio properties (codec, bitrate, sample rate, channels, bits per sample)

### Change History
- **Full audit trail** of every metadata change with old and new values
- **Revert** individual changes or bulk-select and undo multiple edits at once
- Searchable history with shift+click and ctrl+click multi-selection
- Per-song and per-folder history views

### Music Player
- **Built-in audio player** with interactive waveform visualization (WaveSurfer.js)
- Play/pause, previous/next track navigation
- Click-to-seek on the waveform
- Auto-advance to next song
- Collapsible sidebar player with album art, title, and artist display
### Library Browsing
- **Three-panel layout** — folder tree, song list, and detail editor side by side
- **Folder tree** with hierarchical navigation and real-time search
- **Sorting** on any column — title, artist, album, year, duration, bitrate, date added, and dozens more
- **Advanced filtering** — text, numeric ranges, date ranges, and boolean filters across all fields
- **Customizable columns** — show/hide any of 40+ columns to match your workflow
- Virtual scrolling and infinite pagination for large libraries
### File Support
| Format | Supported |
|--------|-----------|
| MP3 | Yes |
| FLAC | Yes |
| WAV | Yes |
| AAC | Yes |
| OGG | Yes |
| M4A | Yes |
| WMA | Yes |
| AIFF | Yes |
| Opus | Yes |
Lossless formats are automatically detected and displayed with a badge.
### Mobile Support
Tagr is fully responsive and works on phones and tablets. The mobile UI adapts to smaller screens with:
- **Full-screen panels** with swipe gestures to navigate between folders, song list, and detail editor
- **Expanded music player** with album art, waveform, and playback controls
- **Touch-friendly editing** — all edit actions are always visible (no hover required)
### Additional
- **Single-user authentication** — password-protected access
- **Resizable panels** — drag to resize the three-panel layout to your liking
- **Dark theme** by default
- **Toast notifications** for operation feedback
- **URL-based state** — bookmarkable views with folder, song, sort, and filter state preserved in the URL

---
## Quick Start with Docker
### 1. Clone the repository
```bash
wget https://raw.githubusercontent.com/suitux/Tagr/main/docker-compose.yml
```
### 2. Generate a secret key
```bash
openssl rand -hex 32
```
Copy the output — you'll use it as `AUTH_SECRET` in the next step.
### 3. Configure `docker-compose.yml`
```yaml
services:
tagr:
image: ghcr.io/suitux/tagr:latest
container_name: tagr
restart: unless-stopped
ports:
- "3000:3000"
environment:
- PUID=1000
- PGID=1000
- NODE_ENV=production
- DATABASE_URL=file:/data/tagr.db
- AUTH_SECRET=paste-your-generated-secret-here
- AUTH_USER=admin
- AUTH_PASSWORD=your-password-here
- AUTH_URL=https://your-domain.com
volumes:
- sqlite_data:/data
# Mount your music folder into the container:
- /path/to/your/music:/music
volumes:
sqlite_data:
```
> **Multiple folders:** If your music is spread across different host paths, mount them as subdirectories under `/music`. Tagr scans `/music` recursively, so all subdirectories are included automatically:
>
> ```yaml
> volumes:
> - /home/user/Music:/music/library
> - /mnt/nas/Music:/music/nas
> ```
>
> Set `MUSIC_FOLDERS` only if you want to **restrict** scanning to specific subdirectories (e.g., scan `/music/library` but skip `/music/podcasts`).
### 4. Build and run
```bash
docker compose up -d
```
### 5. Open your browser
Navigate to [http://localhost:3000](http://localhost:3000), log in with your credentials, and hit the **scan** button to index your library.
---
## Manual Installation
Requirements: **Node.js 22+**.
```bash
git clone https://github.com/suitux/Tagr.git
cd tagr
pnpm install
```
Create a `.env` file in the project root:
```env
DATABASE_URL=file:./data/tagr.db
AUTH_SECRET="c5398a60cfd61607192d74ae8db237aaeaa07a98cd8ecdb8776c86eb87376ba3"
AUTH_USER="admin"
AUTH_PASSWORD="admin"
# Music folders (comma-separated paths)
# Example: /Users/youruser/Music,/Volumes/External/Music
MUSIC_FOLDERS="/Users/youruser/Music,/Volumes/External/Music"
```
Then start:
```bash
pnpm build && pnpm start # Production
# or
pnpm dev # Development mode
```
---
## Environment Variables
| Variable | Required | Description |
|----------|----------|-------------|
| `DATABASE_URL` | Yes | SQLite database path. Use `file:/data/tagr.db` in Docker or `file:./data/tagr.db` locally. |
| `AUTH_SECRET` | Yes | Secret for signing JWT sessions. Generate with `openssl rand -hex 32`. |
| `AUTH_USER` | Yes | Login username. |
| `AUTH_PASSWORD` | Yes | Login password (plain text). |
| `MUSIC_FOLDERS` | No | Comma-separated list of paths to music directories. Defaults to `/music` if not set. |
| `PUID` | No | User ID for the container process. Defaults to `1000`. (Docker only) |
| `PGID` | No | Group ID for the container process. Defaults to `1000`. (Docker only) |
---
## Docker Volumes
| Container Path | Purpose |
|----------------|---------|
| `/data` | SQLite database. Persist with a named volume to avoid data loss. |
| `/music/*` | Mount points for your music libraries. |
---
## Architecture
```
Browser (React Query) --> Next.js API Routes --> Prisma --> SQLite
|
node-taglib-sharp --> audio files on disk
```
| Layer | Technology |
|-------|------------|
| Frontend | React 19, TanStack Query, Shadcn UI, Tailwind CSS 4 |
| Backend | Next.js 16 App Router (route handlers) |
| Database | SQLite via Prisma 7 + LibSQL |
| Auth | NextAuth 5 (credentials provider, JWT sessions) |
| Metadata Read | music-metadata |
| Metadata Write | node-taglib-sharp |
| Audio Player | WaveSurfer.js |
---
## License
MIT