The dead-simple, self-hosted library and download portal for your game collection.
Point it at a folder, hit scan, and browse your games in a beautiful web UI — like a media server, but for games.
Get started · Features · Configuration · Development · License
Self-hosting your game collection shouldn't require a wiki. GameLedger is built to be boring to run and delightful to use:
- 🟢 One file, one command. A single
docker-compose.ymlanddocker compose up -d - 📦 Prebuilt images. Pull ready-to-run
amd64/arm64images straight from the registry, works in any docker environment (Unraid, RPi etc.) - 🪄 Sensible defaults. Just works out of the box the only thing you must set is a password.
- 🎨 Enjoyable UI Cover art, hero pages, screenshots and full IGDB integration, not just a file listing.
New to self-hosting? The 2-minute tutorial below assumes nothing.
- 🔍 Automatic scanning & matching — drop game folders in, GameLedger finds them and matches metadata via IGDB.
- 🖼️ A real library — covers, hero backgrounds, screenshots and accent-coloured detail pages, plus home-page shelves (Recently Added, Most Downloaded, Newest Releases) you can reorder and toggle.
- ✍️ Custom games — got something IGDB doesn't know? Pick the folder, add your own art and details, and it's catalogued just like everything else.
- ⬇️ One-click downloads — resumable, with friendly filenames and per-game download counts.
- 📡 Live progress — scan and compression progress streams to your browser in real time.
- 🔒 Comprehensive Auditing — whatever you, the system or the scheduler does, theres a Logs page under settings that never leaves you lost
- A machine with Docker and Docker Compose (Docker Desktop includes both).
- A folder containing your games (a game is either a folder or a .zip file, just drop it into your library folder)
mkdir gameledger && cd gameledger
curl -O https://raw.githubusercontent.com/dev-nick421/gameledger/main/docker-compose.yml
curl -O https://raw.githubusercontent.com/dev-nick421/gameledger/main/.env.example
cp .env.example .envADMIN_PASSWORD=pick-a-strong-password # required: protects the admin area
LIBRARY_PATH=/path/to/your/games # the folder containing your games (a game is either a folder or a .zip file)docker compose up -dThat's it. Open http://localhost:8080 in your browser. (Change the port with WEB_PORT if 8080 is taken.)
- Click Login (top right) and sign in with your
ADMIN_PASSWORD. - Go to Settings → IGDB and paste your free IGDB API credentials —> needed to fetch cover art and metadata.
- Go to Settings → Paths, add your library path (
/gameswill be yourLIBRARY_PATHinside the container), and save. - Open the Scan dashboard and hit Scan Library. Watch the progress roll in.
- Head back to the Library and enjoy your collection. 🎉
Updating:
docker compose pull && docker compose up -d. Your data lives in a Docker volume, so it survives upgrades. Pin a version withIMAGE_TAG=v1.0.0in.env.
Everything is configured through .env (see .env.example):
| Variable | Required | Default | Description |
|---|---|---|---|
ADMIN_PASSWORD |
✅ | — | Password for the admin area. The app won't start without a non-default value. |
LIBRARY_PATH |
✅ | ./games |
Host folder mounted as your game library. |
WEB_PORT |
8080 |
Host port for the web UI. | |
IMAGE_TAG |
latest |
Pin a specific release, e.g. v1.0.0. |
|
MATCH_THRESHOLD |
0.6 |
IGDB auto-match confidence (0–1); below this, games are left Unmatched. | |
IGDB_CLIENT_ID / IGDB_CLIENT_SECRET |
— | Optional; can also be entered in the UI after first run. |
The API runs only inside the Docker network — nginx in the web container proxies
/api and /ws to it, so there's no extra port to expose or secure.
- Scan — finds folders/zips in your library and queues them.
- Match — IGDB auto-match; uncertain results become correctable Unmatched games instead of bad data.
- Fetch — downloads metadata, cover, background and screenshots; extracts accent colours for the hero gradient.
- Compress — streams the game into
data/<name>.zipinside its own folder; the original is removed only after success. - Browse & download — grid and detail views, with resumable downloads.
Each game lives in its own folder named from the configurable scheme (default
<Game Name> - <Release Year> [<IGDB_ID>]), with data/ for the archive and
artwork/ for images. Display names are generated at read time, so renaming the
scheme never moves a file.
# API → http://localhost:3000
cd api && npm install && npm run dev
# Web → http://localhost:5173 (proxies /api and /ws to the API)
cd web && npm install && npm run devRun the tests:
cd api && npm test # API integration, scanner, IGDB seams
cd web && npm test # Vue components + storesBuild the images yourself:
docker build -t gameledger-api ./api
docker build -t gameledger-web ./webPushing a vX.Y.Z tag builds multi-arch (amd64 + arm64) images, publishes
them to ghcr.io/<owner>/gameledger-{api,web}, and cuts a GitHub Release.
git tag v1.0.0
git push origin v1.0.0Issues and pull requests are welcome. Run npm test in both api/ and web/
before opening a PR, and keep changes focused.
GameLedger is a tool for managing and self-hosting your own, legitimately owned games. It does not provide, host, or facilitate access to any copyrighted content.
GameLedger does not condone piracy. Distributing or downloading games you do not own or have not licensed is illegal in most jurisdictions and a violation of the rights of developers and publishers. You are solely responsible for ensuring that the content you manage with this software complies with applicable copyright law and any relevant license agreements.
GameLedger is free software under the GNU Affero General Public License v3.0 or later. If you run a modified version as a network service, you must offer your users its source.