DuarteSantos8/openGym

▲ 11,693 stars today★ 20,268⑂ 2,703

Open-source gym & body-weight tracker, now in the App Store (iPhone + Apple Watch) and as an Android APK. Plan routines, log workouts, see which muscles are trained, import from Strong/Hevy/FitNotes.

About DuarteSantos8/openGym

DuarteSantos8/openGym is an open-source project on GitHub, mainly written in JavaScript. Open-source gym & body-weight tracker, now in the App Store (iPhone + Apple Watch) and as an Android APK. It currently holds 20,268 stars and 2,703 forks with 298 open issues, and was last pushed on 2026-11-08 (repository created 2026-07-18).

Project Overview

Git Homed tracks it on the Today's Trending board.

GitHub Repository Details

Repository DuarteSantos8/openGym · default branch main · size 348742 KB · watchers 42 · source: GitHub REST API and repository README

README

https://github.com/DuarteSantos8/openGym/blob/HEAD/openGym: the gym tracker you host yourself

https://github.com/DuarteSantos8/openGym/blob/HEAD/Discord https://github.com/DuarteSantos8/openGym/blob/HEAD/Stars https://github.com/DuarteSantos8/openGym/blob/HEAD/Release https://github.com/DuarteSantos8/openGym/blob/HEAD/Downloads https://github.com/DuarteSantos8/openGym/blob/HEAD/Tests https://github.com/DuarteSantos8/openGym/blob/HEAD/AGPL-3.0

https://github.com/DuarteSantos8/openGym/blob/HEAD/Download on the App Store https://github.com/DuarteSantos8/openGym/blob/HEAD/Download the Android APK https://github.com/DuarteSantos8/openGym/blob/HEAD/Self-host with Docker

https://github.com/DuarteSantos8/openGym/blob/HEAD/DuarteSantos8%2FopenGym | Trendshift https://github.com/DuarteSantos8/openGym/blob/HEAD/DuarteSantos8%2FopenGym | Trendshift

Website · Live demo · Roadmap · Changelog

https://github.com/DuarteSantos8/openGym/blob/HEAD/Buy me a coffee https://github.com/DuarteSantos8/openGym/blob/HEAD/Support openGym on Ko-fi

Why openGym

Most workout apps keep your data on their servers, push you towards a subscription, or vanish when the company does. openGym runs on your own box, keeps your data in a folder you control, and is yours to fork. It still behaves like a modern app: installable on the home screen, passkey sign-in, works offline, syncs between your phone and your laptop.

No account on someone else's server, no subscription, no ads, no telemetry. One docker compose up and it's running.

The in-browser demo is the real app with example data, if you want to try it before installing anything.

Features

Planning

browsable by muscle on a body map. Filter by the equipment you own. editable routines. works lit up, so you know Leg Day is legs before you open it. Sunday, your choice. simply the next one you haven't done, however the week went. cardio by time and speed, rest time per exercise, planned deloads. device before upload.

Training

timer runs between sets, PRs are detected as you go. On a rest day it tells you when the next session is. list view. Switches in Settings bring the old button rows back if you liked them. Train in more than one place? Each gym keeps its own plates, dumbbells, bars and machine stacks, and the phone can switch to the gym you just walked into. rest-timer alert can flash the screen for loud gyms. and rest per set, and a scroll wheel for any rest time up to 15 minutes, or no timer at all. Machines can carry their real weight stack, odd steps included, and progression sticks to it. Progress visible rep range, triple progression (reps, then sets, then load), or adding time. Each target explains why it is that number; missed reps never add load, stalls trigger a deload. ATG), a year-long activity heatmap. untrained. range, and progress photos on a timeline with a before/after slider. Records are re-read from the corrected history.

Accounts and data

sign-in can be switched on per instance; new devices pair with a one-time code or QR. sync). everything as one JSON file, or your workouts and body data as a spreadsheet (CSV). instructions are translated for most of them.

On the phone and the wrist

yours. Rest timer in the notification shade, reminders, and Health Connect or Apple Health in both directions: workouts go out, weigh-ins and heart rate per set come back in. Start. Once a day at most, never after you trained, and your gyms stay on the phone. full-screen rest countdown, heart rate per set, a Lock button against stray crown presses, and complications. No watch? AirPods Pro 3 do the heart rate on iOS 26. from the Lock Screen without opening the app.

Only what you use

"Just training" to "Everything". Body, Health, Motivation, the Coach, seasonal themes and more each disappear completely while they're off, and nothing is deleted.

Optional extras, off by default

what you logged, and answers questions about your training. You approve every change. It runs on your server, or on the phone alone, with your own provider key (Anthropic, OpenAI, Gemini or any OpenAI-compatible endpoint, Ollama included). training history, and log a workout you describe to it. Local; not part of the Docker build. Withings and friends come in through them), imports, and signed webhooks to Home Assistant, n8n or ntfy when you finish a workout, set a record or weigh in.

The full list of what changed release by release is in the changelog.

Quick start

You need Docker with Compose.

git clone https://github.com/DuarteSantos8/openGym
cd openGym
cp .env.example .env
docker compose pull      # prebuilt images, amd64 + arm64 (skip this to build from source)
docker compose up -d

Open , tap Create profile, and you're in. The exercise animations are part of the image, so there's nothing else to download.

To reach it from your phone with passkeys you need HTTPS on a domain; that's a two-line change in .env. The self-hosting guide walks through Cloudflare Tunnel, Caddy, Traefik and nginx, and there are separate guides for HTTPS on a LAN, a Mac with Tailscale and Kubernetes.

[!NOTE]
Images are published from the same tag to ghcr.io/duartesantos8/opengym-{api,web}
(what docker-compose.yml pulls) and registry.gitlab.com/duartesantos8/opengym/{api,web}. Swap
the image: lines if you prefer GitLab's registry, or run docker compose up -d --build to build
locally. Either way you don't need Node on the host.
Configuration reference (all through .env)

| Variable | What it does | Default | |---|---|---| | RP_ID | Hostname passkeys are bound to | localhost | | ORIGIN | Full URL the app is served from | http://localhost:8080 | | WEB_PORT | Host port for the web UI | 8080 | | NGINX_PORT | Port the web container listens on inside the container | 80 | | BACKEND | Name of the API service that /api is proxied to | api | | PORT | Port the API listens on; the web container proxies to the same value | 3000 | | RP_NAME | Name shown in the passkey prompt | openGym | | SESSION_DAYS | How long a sign-in lasts, in days | 90 | | ADMIN_UIDS | User ids that get the admin dashboard, comma-separated | (none) | | FIRST_USER_ADMIN | 1: the first profile created on an empty instance becomes its admin | (off) | | INVITE_ONLY | Require an invite code to create a profile | (off) | | ALLOW_GUEST | Offer "Continue without account"; 0 requires a profile | (on) | | PASSWORD_LOGIN | Offer name-and-password sign-in next to passkeys | (off) | | TRUST_PROXY | Let the sign-in throttle read the client address from proxy headers | 1 in docker-compose.yml | | AUDIT_LOG | Record sign-ins and admin actions; 0 records nothing | (on) | | AUDIT_MAX | Events kept in the activity log; 0 for no limit | 5000 | | AUDIT_DAYS | Days kept in the activity log; 0 keeps until AUDIT_MAX | 90 | | AUDIT_IP | Record the caller's address: off, net (network only) or full | off | | ALLOWED_PRIVATE_IPS | Private addresses push endpoints may resolve to (FakeDNS, split-horizon DNS): comma-separated IPs, a-b ranges or CIDR blocks | (none) | | INTEGRATIONS | Server integrations to offer, comma-separated: webhook (integrations) | (none) | | INTEGRATIONS_ALLOW_LAN | 1: webhooks may reach your home network (Home Assistant), http included; never loopback | (off) | | VAPID_SUBJECT | Contact URL sent with push notifications | your ORIGIN | | API_TARGET | API image to build: default, or coach with the Claude Agent SDK and Codex CLI | default | | COACH_DISABLED | 1 forces the AI coach off instance-wide | (unset) |

Push-notification keys are generated on first run into ./data/vapid.json. DATA_DIR is pinned to /data inside the container and mapped to ./data on the host; change the volume, not the variable. The self-hosting guide covers every option in detail.

Phone app

The same codebase builds the phone apps with Capacitor. Use them on their own (everything stays on the phone, no account) or connect them to your server and sync.

| | Get it | |---|---| | iPhone and iPad, with the Apple Watch app | The App Store, in every App Store country | | Android | The signed APK from the latest release or opengym.ch, in three sizes: Standard (openGym-X.Y.Z.apk, animations at 180 px, about 315 MB), Plus (openGym-Plus-X.Y.Z.apk, 240 px, about 424 MB) and HD (openGym-HD-X.Y.Z.apk, 360 px, about 760 MB). It updates itself and stays the kind you picked | | Google Play | In closed testing: Google wants 12 testers for 14 days before it lets everyone in. Join the tester group, then opt in. It installs right over the APK and keeps your data | | Wear OS watch (beta) | Rides along with the Google Play test: once Google's watch review is done, "openGym Beta" shows up in the Play Store on your Galaxy Watch, Pixel Watch and friends. Details: docs/WEAR_OS.md |

Every APK sits next to its .sha256. The APK and the Play app share one signing key, so you can switch between them (or between Standard, Plus and HD) without losing data. Details, building it yourself and connecting to your server: docs/MOBILE.md.

How it works

https://github.com/DuarteSantos8/openGym/blob/HEAD/Architecture: the phone talks HTTPS to nginx (web), which serves the app and proxies /api to the Node api; the api stores JSON in ./data. The exercise media ship inside the web image; the AI coach and MCP server are optional.

web-push for notifications and undici for the AI coach's provider calls. Everything is stored as JSON under ./data. one origin, which passkeys require.

The architecture overview has the longer version, with diagrams of the frontend, sync, the exercise media and the watch.

The training logic (progression rules, 1RM, how a logged session is read back) lives in pure functions under frontend/src/lib/ with tests beside them. The HTTP API is documented as an OpenAPI spec in api/openapi.yaml, browsable at opengym.ch/api.html.

How sync works

Each profile's data is one document with a server revision. A device sends the revision it last saw along with its changes; if another device wrote in between, the server refuses and returns the current document so the device can merge and retry. Every change carries its own stamp, down to a single setting or routine field, so the merge keeps the newest edit of each one and a deletion stays deleted.

https://github.com/DuarteSantos8/openGym/blob/HEAD/Sync: a device saves with the revision it last saw; if another device wrote in between, the server answers 409 with the current document, the device merges and saves again.

Nothing that hasn't reached the server is discarded on disconnect or sign-out, and the app shows a banner whenever it's working offline.

Your data

Everything lives in ./data on your host:

| File | Contents | |---|---| | db.json | Profiles and public passkey data | | db.json.bak | A copy of the last good db.json, used if the main file can't be read | | state-.json | Each user's plan, workouts, body weight and settings | | audit.log | Admin activity log (no IP addresses unless you turn that on) | | secret | Session-cookie signing key |

Back up ./data and you've backed up everything. Passkey private keys never reach the server; they stay in your phone's secure hardware or your password manager.

Documentation

The documentation index sorts every guide by who it's for. The most used ones:

| I want to | Read | |---|---| | Get a quick answer | FAQ | | Set up my own instance | Self-hosting | | Use the Android or iPhone app | Phone app | | Bring my history from another app | Importing data | | Turn on the AI coach | AI coach | | Contribute code | Contributing | | Report a security problem | Security |

Roadmap

A release roughly every one to two weeks, each one whatever has passed testing by then. The full plan is in ROADMAP.md, and the issues sit in the GitHub milestones.

| Release | When | Theme | |---|---|---| | v1.4.0 | released Oct 2026 | A new exercise database with 5,632 exercises, plus two rounds of community work | | v1.4.1 | released Oct 2026 | Bug fixes for v1.4.0 | | v1.4.2 | released Oct 2026 | The App Store, the Apple Watch, widgets, three APK sizes | | v1.4.3 | released Oct 2026 | The Halloween and community release: gym reminder, health data read back, watch upgrades, CSV export | | v1.4.4 | released Nov 2026 | Programmes, a fresh look, Modules, a tour with tutorials, AirPods heart rate, kg or lb per exercise, the Google Play closed test and a Wear OS beta | | v1.4.5 | Nov 2026 | Google Play for everyone, F-Droid, Settings → Integrations (Strava, webhooks, calendar, Nextcloud), timed holds that start themselves | | v1.4.6 | Dec 2026 | Wear OS out of beta, deeper Health Connect, body composition | | v1.4.7 | Dec 2026 | The progression engine by @giulioleuci, circuits, AMRAP and EMOM | | later | dates are guesses | Search and catalogue, accounts, a trainer role, skins, Garmin, database storage |

Community

quick back-and-forth. Usually the fastest way to get an answer. you want the next person to find by searching. work. Login trouble is almost always an RP_ID/ORIGIN mismatch; the self-hosting guide covers it. CONTRIBUTING.md.

https://github.com/DuarteSantos8/openGym/blob/HEAD/Contributors

Where the code lives

GitHub is the home of the project. gitlab.com/DuarteSantos8/opengym is a mirror, updated by a GitHub Actions workflow on every push to main and every release tag. It exists because its CI builds the multi-arch images and the SBOMs for its registry (the APKs are built and signed on the release machine and attached to the GitHub release). Nothing is merged there by hand. In the changelog, !NN refers to a GitLab merge request from the weeks in August and September 2026 when the project lived there.

How openGym is built

People have asked about this, so plainly: openGym is developed with Claude Code, Anthropic's coding agent. A large share of the code, tests and documentation is drafted in Claude Code sessions, and the repository carries a CLAUDE.md with the project context those sessions start from.

What that does and doesn't mean:

are the maintainer's call. Changes are tested on a staging instance and on real phones before they are tagged. run the frontend, API and MCP suites in CI. That is the guard against plausible-looking code that is wrong, whoever or whatever wrote it. coach and the MCP server are opt-in, and the coach only talks to the provider you configure, with your own key.

Community pull requests are written by their authors, with whatever tools they like, and reviewed the same way.

Support

openGym is free and stays free: AGPL, no paid tier, nothing held back for sponsors. If it replaced a paid tracker for you and you'd like to chip in, there's Buy Me a Coffee, Ko-fi and GitHub Sponsors (the app has the same three under Settings → About & updates, and on the iPhone a shortcut to leaving an App Store review). A star, a bug report or a pull request helps just as much.

https://github.com/DuarteSantos8/openGym/blob/HEAD/Buy Me A Coffee https://github.com/DuarteSantos8/openGym/blob/HEAD/Support openGym on Ko-fi

GitHub Sponsors

Star History Chart

License

openGym's own code is licensed under the GNU AGPL v3.0. You can self-host, use, modify and share it; if you run a modified version as a network ser

GitHub Stars & Activity

20,268Stars
2,703Forks
298Open issues
JavaScriptLanguage

GitHub Popularity

GitHub stars20,268
Forks2,703
Open issues298
Primary languageJavaScript
LicenseAGPL-3.0
Stars gained today11,693
Created2026-07-18
Last pushed2026-11-08

Trending History

Monthly boardrank #30 · ▲ 11,693 stars

Related GitHub Projects

1

addyosmani / agent-skills

JavaScript★ 115,516⑂ 12,118▲ 465 stars
→
2

chinese-poetry / chinese-poetry

JavaScript★ 54,283⑂ 10,944▲ 53 stars
→
3

Anil-matcha / Open-Generative-AI

JavaScript★ 34,012⑂ 6,473▲ 263 stars
→
4

chuspeeism / dashi-ppt-skill

JavaScript★ 10,599⑂ 901▲ 47 stars
→
5

tiagozip / cap

JavaScript★ 8,330⑂ 650▲ 32 stars
→
6

PenglongHuang / chinese-novelist-skill

JavaScript★ 4,784⑂ 649▲ 67 stars
→
7

kunchenguid / lavish-axi

JavaScript★ 4,532⑂ 418▲ 50 stars
→
8

mattpocock / skills

Shell★ 321,452⑂ 26,944▲ 1,225 stars
→

More Trending Repositories