Self-hosted service
DuarteSantos8/openGym avatar
DuarteSantos8/openGym

openGym: a self-hosted workout tracker built around progressive overload rules

Self-hosted gym & body-weight tracker — plan routines, log workouts (supersets, warm-ups, cardio), see which muscles are trained, fatigued or detrained, import from FitNotes/Strong/Hevy, passkey login. Your data, your server.

892 stars201 forksJavaScriptAGPL-3.0

At a glance

What is it?
openGym is an AGPL-3.0 self-hosted gym and body-weight tracker in JavaScript, shipped as a Docker Compose stack with passkey login and import from FitNotes, Strong and Hevy. Its distinguishing feature is that progression is computed from named rules rather than guessed, and the fatigue map only counts the sets that should count.
Who is it for?
Adopt openGym if you already run Docker Compose on a machine you control, you train with barbell or bodyweight progression and you want your set history in a folder you can back up. Do not adopt it if you want a vendor to run the database, if you need native iOS or Android apps, or if you train in a commercial gym where a phone browser and a self-hosted endpoint are a nuisance.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem openGym targets: your training log lives on someone else's server

The README states the motivation directly: most workout apps lock your data behind a login on their servers, nag you to upgrade, or disappear when the startup does. That is the failure mode openGym is built against. The audience is narrow and identifiable: people who already self-host, who train with a written plan rather than improvising, and who care that a year of set-by-set history is not a row in a company's database. The README also names the import path explicitly (FitNotes, Strong, Hevy), which tells you the intended user is someone with an existing log, not someone starting from zero. The feature list is written for a lifter who tracks load and reps seriously: estimated 1RM, per-exercise weight tracking, PR detection, and a fatigue map that separates trained, fatigued and detrained muscles. This is not a general wellness or step-counting app. It is a barbell log with a weekly plan attached.

How progression is decided, and why the rule matters more than the chart

Most of the mechanism visible in the README sits in the progression layer. The documentation states that you pick one progression rule per routine and can override it per exercise, from a set that includes linear, Greyskull LP (described as AMRAP top set, double jumps and 10 percent resets), double progression through a rep range, and adding time. The README claims every target says why it is that number, that missed reps never advance the load, that stalls trigger a deload, and that bodyweight exercises progress in reps instead. That last point is where the design gets specific. A bodyweight exercise carries no load, so it has no weight column and no working-weight prompt; if you add a dip belt it reads as an addition and progression returns to following the weight. Without one, reps climb until a ceiling you set, at which point the app adds a set instead of a rep. That ceiling is a user setting, not a heuristic, which is the honest way to handle it. The same care shows in rep targets for unilateral work: you log the total, the app shows the split, and the target steps in twos so it never lands on a number one side cannot have.

Warm-up sets, supersets and the fatigue map: what gets excluded

The exclusion rules are the part worth reading closely, because they determine whether the numbers you look at mean anything. Warm-up rows are marked as such and stay out of estimated 1RM, progression and the fatigue map, while remaining visible in the session. The README adds a detail that suggests real use: a weight change cascades down the rows sharing their phase, not across the divide between warm-up and working sets. Supersets can be planned into a routine or created mid-session by pairing an exercise with the previous or next one, and the group is worked back-to-back with a single rest at the end of each round. Unpairing is allowed at any time, and a group of one dissolves itself. Two smaller decisions reinforce the same theme. Removing an exercise that belongs to a superset asks which one you meant. Effort rating (RIR or RPE) is off by default, each set keeps the scale it was logged with, and nothing else reads the value, so progression and 1RM are unaffected. That is a deliberate refusal to let a subjective rating contaminate the load calculation, and it is the right call.

Installing openGym with Docker Compose and passkey login

The README gives one install instruction in its opening lines: docker compose up. That is the whole documented deployment path, and it is consistent with the Docker Compose badge and the self-hosted framing. What the README does not give is a compose file, an environment variable list, a volume path for the data directory, or a reverse-proxy example. The homepage at opengym.duarte-santos.ch is the live instance, and the README points to a separate browser-only demo on GitHub Pages that runs on example data with no server behind it. The README is explicit that in that demo, passkey sign-in, sync across devices and the admin dashboard do not exist, because there is no server. So the honest position on setup is this: the deployment unit is a Compose stack and the authentication method is WebAuthn passkeys, but the specifics of ports, volumes and the WebAuthn relying-party origin have to come from the repository itself, not from the README text. Anyone deploying this behind a reverse proxy should expect to configure the passkey origin deliberately, since WebAuthn binds credentials to a domain and a wrong origin is a silent login failure rather than an error message.

What openGym does not do, and where it is the wrong tool

There is no native mobile application in the material. The delivery target is an installable PWA, which the README frames as a home-screen app with offline support. That is a real constraint: on iOS, background behaviour, storage eviction and screen wake behaviour are governed by the browser, and the README's claim that the screen stays awake for the duration of a workout is implemented through that layer. If the browser revokes it, you are unlocking your phone between sets, which is exactly the annoyance the feature exists to remove. Sync is described as across your devices, which in a self-hosted single-server design means your devices reach your server; if the server is on your home network and you train at a commercial gym, you need that server reachable from outside, and the README does not discuss that. The exercise library is stated as 1,324 exercises with animated demos, and the equipment filter narrows it to what you own. A lifter whose programme is built on machines or movements outside that library can add custom exercises (a name and a body part is enough, with an optional description instead of an animation), but the animation is gone. Finally, the import path from FitNotes, Strong and Hevy is named but not specified. Whether supersets, warm-up flags and timed sets survive that import is the single most important thing to test before you migrate years of history.

openGym against a hosted tracker like Strong or Hevy

The comparison is not about feature counts. Strong and Hevy are hosted services: you install their app, create an account, and their servers hold the log. They handle sync, backups, app-store distribution and the case where you switch phones without thinking about it. openGym inverts every one of those. You run the server, you own the database file, you are the person who notices when the disk fills or the container stops. In exchange, no subscription, no ads, and no dependence on a company continuing to exist. There is a second difference that matters more for training than for infrastructure: openGym treats progression as an explicit, inspectable rule attached to a routine, with named algorithms and a stated reason for each target. Hosted trackers generally show you history and let you decide the next load yourself. If you want the app to tell you what to put on the bar and why, that is openGym's actual selling point. If you want the app to stay out of the way and just record, the extra machinery is overhead.

Licence, maintenance and the cost of running your own log

openGym is AGPL-3.0. For a self-hoster running it on a personal server, the practical effect is close to nil: you are not distributing modified versions. The obligation becomes relevant if you fork it and expose the modified version to users over a network, because the AGPL's network clause requires offering the corresponding source to those users. That is a description of the licence, not legal advice; read the LICENSE file and take counsel if you plan to build a service on a fork. On maintenance, the release history shows v1.2.5, v1.2.6 and v1.2.7 within roughly two weeks of each other in August 2026, and the last push to main is dated the same day as the newest release. That cadence means frequent image pulls if you track releases, and it also means the project is active rather than abandoned. The upgrade cost is whatever your Compose workflow charges you: pull the new image, restart, and check that the database schema migrated. The README does not describe a migration or backup procedure, so a copy of the data volume before each upgrade is the only safe assumption until you find one in the repository.

Editorial conclusion

Adopt openGym if you already run Docker Compose on a machine you control, you train with barbell or bodyweight progression and you want your set history in a folder you can back up. Do not adopt it if you want a vendor to run the database, if you need native iOS or Android apps, or if you train in a commercial gym where a phone browser and a self-hosted endpoint are a nuisance. Before committing, verify three things on your own instance: that a passkey can be registered and used from every device you train with, that an export from FitNotes, Strong or Hevy imports without losing supersets or warm-up flags, and that the progression rule you actually follow (linear, Greyskull LP, double progression or time) is one the routine editor offers. The live demo at duartesantos8.github.io/openGym runs on example data with no server behind it, so it cannot answer any of those three.

Official sources

  1. DuarteSantos8/openGym on GitHub
  2. License: AGPL-3.0
  3. Project website
  4. README
  5. Releases
Community notes

Community notes