# Ganymede: a Twitch archiving platform that renders chat into standalone files

> Ganymede is a Go service, deployed as two Docker containers, that archives Twitch VODs and live streams, replays chat in real time, and writes each archive to disk in a layout that stays readable without the software.

**Zibbp/ganymede** — Twitch VOD and Live Stream archiving platform. Includes a rendered and real-time chat for each archive.

- Repository: https://github.com/Zibbp/ganymede
- Website: https://github.com/Zibbp/ganymede
- Stars: 1,017 · Forks: 63
- Language: Go
- License: GPL-3.0
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/zibbp-ganymede

## The archive is designed to outlive the software

Ganymede archives past broadcasts and live streams from Twitch, and the central design decision is that the output does not depend on the program. Files are saved in a format that can be used without Ganymede, and every archive includes a rendered chat, so the video and the conversation can be watched outside the tool. The feature list names the file structure as a simple layout for long-term archival that will outlast Ganymede, with the details in a wiki page on file structure. The project is also the successor to an earlier archiving platform called Ceres, and it is licensed under GPL-3.0. Around the archiving core sit the ordinary features of such a service: full VOD, channel and user management, watched channels with advanced filtering, playlists, playback with progress saving, webhook notifications, and a recoverable queue system.

## A Twitch application, Docker on Linux and fifty gigabytes

The requirements are short and specific. You need a Linux environment with Docker, optionally a network mounted storage volume, a Twitch application created through the Twitch developer console, and 50 GB or more of free storage with a separate wiki page for the storage requirements. The Twitch application is not optional, because the service authenticates against the Twitch API, and the compose file asks for a client id and a client secret to be filled in. The storage figure is the number most likely to surprise people, since a back catalogue of channels is measured in tens of gigabytes before chat rendering is added, and the video directory is where all of it lands.

## Two containers, an admin account and a password change

The deployment is a server container and a Postgres database container, and the documentation notes that you can point the server at an existing Postgres container instead of starting a new one. The install is a matter of downloading the `docker-compose.yml` file, editing the environment variables it contains, starting the stack and changing the default credentials.

```bash
docker compose up -d
```

You then visit the address and port you set for the frontend and log in with the username `admin` and the password `ganymede`. The documentation is explicit about the next step: change the admin password or create a new user, grant that user admin permissions, and delete the admin user. That last instruction is the difference between a default install and a locked down one, and skipping it leaves a known password on a service that can download and serve video and accept credentials for Twitch.

## Four tag styles decide which build you run

Images are published to ghcr.io and there are four kinds of tag. `latest` points to the latest release. A semver tag such as 4.10.0 gives the latest release in semver format. `dev` is a build of the main branch, intended for testing new features before a release. A pull request tag such as `pr-123` is a build of that pull request, and it is deleted when the pull request is closed. That last behaviour is worth remembering, because a container image referenced by a pull request tag will stop existing at an unpredictable time. The published releases are frequent, with v4.21.0 on 2026-09-22, v4.20.0 on 2026-08-25 and v4.19.1 on 2026-08-12, and the last push to the repository was on 2026-10-15.

## Rootless mode trips over network storage that cannot chown

The API container can run as a non-root user, which is enabled by setting the `PUID` and `PGID` environment variables to the values of your own user, following the convention used by LinuxServer containers. On startup the container chowns the config, temp and logs directories, but it does not recursively chown the videos directory, so you have to make sure the mounted video path is readable by the set user. That omission becomes a real problem on network shares, and the documentation covers it: if the storage cannot support chown, such as an NFS or SMB mount with NFSv4 ACLs on TrueNAS for example, set `SKIP_CHOWN=true` and make sure the directories are already writable by the set user. Configuration is a JSON file generated on first start, by default at `/data/config/config.json`, and most settings are also editable in the web interface under Admin and Settings.

## Concurrency per task type is the knob that matters

The compose file exposes a separate worker limit for each kind of background job, which is how you keep a large archive from saturating the disk or the CPU.

```yaml
  - MAX_CHAT_DOWNLOAD_EXECUTIONS=3
  - MAX_CHAT_RENDER_EXECUTIONS=2
  - MAX_VIDEO_DOWNLOAD_EXECUTIONS=2
  - MAX_VIDEO_CONVERT_EXECUTIONS=3
  - MAX_VIDEO_SPRITE_THUMBNAIL_EXECUTIONS=2
```

There is also a pair of settings for live archive stall detection, where the stall check can be disabled and the timeout is set in seconds with a documented minimum of 30, defaulting to 180. Behind those environment variables sits a real architecture: the Go module depends on the River queue library with its SQL driver and a web interface for it, on the ent entity framework for the schema, on Echo for the HTTP layer, and on swaggo for the generated API documentation that lives in the docs folder.

## The archiving tools are pinned versions inside the image

The container does not install the tools it needs at runtime. The Dockerfile pins versions at build time, with TwitchDownloader at 1.56.5, yt-dlp at 2026.07.04 and FFmpeg at 9.0, and it builds yt-dlp from source in a separate stage. It even selects between the Linux x64 and arm64 TwitchDownloader archives depending on the architecture. One detail shows the seam of this arrangement: the repository contains a patch file for yt-dlp adapted for Twitch, and the corresponding apply step in the Dockerfile is commented out, so the patch is present in the tree without being applied in the current build. Two further areas are worth a mention. Authentication can be extended with OAuth or single sign-on through the documented provider settings, and translations live as JSON files in the frontend messages directory, with a script that reports coverage and a flag to fill in missing keys.

## Conclusion

Ganymede suits people who want to keep Twitch broadcasts and their chat for the long term and do not mind running two containers, Postgres and a fair amount of disk. It is the wrong choice for a quick download, since the archiving stack is built around a persistent queue, a database and background workers rather than a one-off script. Before you start, create the Twitch application and set the client id and secret, decide where the video directory lives, and check the 50 GB storage guidance, because a large back catalogue will need more than the minimum.

## FAQ

### What does Ganymede do with Twitch streams?

It archives past broadcasts and live streams, replays the chat alongside them, and renders a chat track into each archive. The files are written in a layout that can be viewed without Ganymede itself.

### What do I need before installing Ganymede?

A Linux environment with Docker, a Twitch application created in the Twitch developer console, and 50 GB or more of free storage. Network mounted storage is optional.

### How do I run Ganymede as a non-root user?

Set the PUID and PGID environment variables to your own user and ids. On startup the container chowns the config, temp and logs directories but not the videos directory, and if your storage cannot chown, such as NFS or SMB, set SKIP_CHOWN=true and ensure the directories are writable already.

### Where is the Ganymede API documentation?

In the docs folder of the repository, generated with swaggo from the server entry point, alongside a wiki with in-depth documentation on features.

## Sources

- [License: GPL-3.0](https://github.com/Zibbp/ganymede/blob/main/LICENSE)
- [Project website](https://github.com/Zibbp/ganymede)
- [README](https://github.com/Zibbp/ganymede/blob/main/README.md)
- [Releases](https://github.com/Zibbp/ganymede/releases)
- [Zibbp/ganymede on GitHub](https://github.com/Zibbp/ganymede)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/zibbp-ganymede
