RetroArr

Self-hosted game library manager for PC and retro consoles.

Website License Docker Releases

--- Think Radarr/Sonarr, but for video games. RetroArr scans your library, fetches metadata, organizes files, searches indexers, and automates downloads across PC, retro consoles, handhelds, and arcade platforms. One tool, one UI. ## Quick Start ```yaml # docker-compose.yml services: retroarr: image: ghcr.io/riddix/retroarr:latest container_name: retroarr ports: - "2727:2727" # HTTP - "2728:2728" # HTTPS (optional, self-signed cert) volumes: - ./config:/app/config - /your/games/path:/media - ./savestates:/app/savestates environment: - PUID=1000 - PGID=1000 - RETROARR_HTTPS_PORT=2728 # remove to disable HTTPS restart: unless-stopped ``` ```bash docker compose up -d ``` Open `http://your-ip:2727` (or `https://your-ip:2728`), then **Settings → Metadata** and paste your [IGDB credentials](https://api-docs.igdb.com/#getting-started) (free, Twitch dev account). ## HTTP or HTTPS? Both are served by the same container. Pick what fits your setup: - **HTTP on `:2727`**: fine for localhost, or when you already have a reverse proxy (SWAG, Traefik, Caddy, nginx) handling TLS - **HTTPS on `:2728`**: auto-generated self-signed cert on first start, stored in `config/certs/retroarr.pfx`. Required for threaded emulator cores (PSP, NDS, N64, Saturn, 3DO) when you access the UI from a LAN IP, because browsers only expose `SharedArrayBuffer` on secure origins If you only plan to proxy through SWAG with a real cert, drop the `2728` line from `ports:` and the `RETROARR_HTTPS_PORT` env var. ## Features **Library & scanning** - Identifies files across **170 platforms** from `PlatformDefinitions.cs`: PC, every PlayStation, every Xbox, Nintendo NES through Switch 2, Sega from SG-1000 to Dreamcast, Atari, NEC, Arcade (MAME, FBNeo, CPS, Neo Geo), ScummVM, DOSBox, plus a pile of obscure handhelds and 8-bit computers - Metadata from **IGDB** (primary), **ScreenScraper** (retro and arcade fallback), **Steam**, and **GOG** - PlayStation serial extraction (SCES/SCUS/SLUS/SLES/CUSA/PPSA/…) so the title gets cleaned and metadata finds the right entry - Nintendo Switch Title ID parsing (base vs patch vs DLC via bit flags) - Region, language and revision tags parsed from filenames - Multi-file games: `.cue` + `.bin`, `.m3u` for multi-disc, `.gdi` tracks, folder-based PS3/Wii U, `.chd`, `.nsz`/`.xcz` - Rescan heals wrong platforms by re-reading the path, deduplicates after folder moves **Downloads & indexers** - Indexer backends: **Prowlarr**, **Jackett**, **Hydra Launcher** - Download clients: **qBittorrent**, **Transmission**, **Deluge**, **SABnzbd**, **NZBGet** - Post-download handler picks the right platform folder, renames, attaches patches/DLC to the right game - Monitoring (Sonarr/Radarr-style): flag a game — or a whole platform — as monitored, and a background sweep searches your indexers on a schedule and can auto-grab the best-scoring release. Clickable monitor markers sit on the library cards and the game detail page; the platform toggle bulk-applies to every game and sets the default for newly scanned ones **LanCache** - Point RetroArr at your [LanCache](https://lancache.net/) under Settings → LanCache; it checks reachability via the cache heartbeat and reconciles your Steam library against it - Warm the cache with the bundled prefill tools for **Steam**, **Battle.net** and **Epic** ([tpill90](https://github.com/tpill90)'s `*-lancache-prefill`), driven from the UI with a live log. See [LanCache & Prefill](docs/LANCACHE_PREFILL.md) **Launching** - Steam and GOG launch directly through their clients when the game is installed there - Native executable discovery for installed PC games - Linux: Proton/Wine auto-detection, per-game runner override, Lutris config export, Steam shortcut export, `.desktop` file generation - macOS: opens via `/usr/bin/open`, delegates to Whisky/CrossOver when present **Emulation** - Browser-based retro emulation via [EmulatorJS](https://emulatorjs.org/) with 23 cores wired up: NES, SNES, N64, GB, GBC, GBA, NDS, VB, Genesis, Master System, Game Gear, Saturn, 32X, Sega CD, PS1, PSP, Atari 2600/5200/7800/Lynx/Jaguar, Arcade, PCEngine - BIOS drop folder at `/app/config/bios`, whitelisted filenames served to EmulatorJS on demand - Save states: 8 slots per game, upload/download/delete from the UI, stored in `/app/savestates` **UI & integrations** - Retro-themed interface with CRT boot animation, platform-accent color tinting, keyboard d-pad navigation - 7 UI languages (English, German, Spanish, French, Russian, Chinese, Japanese) - Plugin system: process-isolated, language-agnostic, with circuit breaker and JSON stdin/stdout - Webhook notifications (Discord-compatible) with in-UI test button - Nintendo Switch USB transfer via DBI protocol (Python helper ships with the container) - Real-time scan / download / health status over SignalR, with a LIVE badge in the sidebar **Storage & deployment** - Database: **SQLite** (default), **PostgreSQL**, or **MariaDB**. Migration between them is a guided flow in Settings → Database - Optional **Redis** cache - Structured logging, per-feature log files, rotation, one-click diagnostics export - Docker image runs as non-root, has a `HEALTHCHECK`, works on `amd64` + `arm64` **Security** - Every stored credential (IGDB, ScreenScraper, download clients, Steam, Prowlarr, Jackett, GOG) encrypted with ASP.NET Data Protection. Plaintext values from older installs get migrated on first save - API key gate: everything needs `X-Api-Key`, except in the desktop app, where requests that really come from the same machine (loopback socket peer, a `localhost`/loopback `Host` and `Origin`, no proxy headers, not a cross-site browser request) are unauthenticated. Headless and Docker installs never treat a request as local, so a reverse proxy on the same host can't open the API; the UI asks for the key, which is in `apikey.json` in the config folder (path printed at startup). Key is shown and rotatable in Settings → API access - EmulatorJS static assets and the `/emulator/player` page are exempt from auth, since browsers can't attach API keys to `