openexercisedb

September 5, 2026 · View on GitHub

An open, structured, machine-readable strength-training exercise database.

Every exercise is a plain text file you can read, diff, and send a pull request against. Every release ships a single SQLite file you can drop into an app.

Status: initial release. The database is published and ready for use. All 868 active exercises carry a full set of attributes and complete text in English, German, French, Italian, and Japanese. Releases are published to the catalog-stable channel. See Where it stands and Roadmap.


Why this exists

The best freely licensed exercise dataset available today is the one from the wger project. It is a genuine public good and this project is a fork of it. It is also, measured against what a training app needs, incomplete in specific and fixable ways.

At the time of the import (2026-09-02, 871 exercises) — and where the same measurements stand today:

At importToday
Exercises with no muscle assignment at all129 (15%)0
Exercises with no primary muscle135 (16%)0
Distinct muscle values in use1551 (of 69 in the vocabulary)
Exercises with no German description243 (28%)0
Exercises with a full attribute set0868 of 868

Fifteen values, mixing coarse groups (Chest, Shoulders) with single anatomical muscles (Obliquus externus abdominis, Soleus, Brachialis). No front/side/rear deltoid split. No forearms, adductors, spinal erectors, rhomboids, or rotator cuff at all.

There is also no structured way to express things a training app needs on every screen: what equipment an exercise requires, whether it is a warm-up or a main lift, whether it is logged in reps, seconds, or kilometres. In the upstream schema category is simultaneously a body region (Legs, Back) and a training type (Cardio), so "is this a cardio exercise?" ends up being a string comparison against a body part.

openexercisedb keeps the upstream identifiers and attribution intact, and fixes the model.

What's different

Muscles are a hierarchy, and you may annotate at any depth. 14 groups → 33 muscles → 22 heads. If you are confident an exercise hits the long head of the triceps, say so. If you are only confident it is triceps, say that. If you are only confident it is arms, say that. Every level resolves upward, so statistics always work — and "which entries still lack head-level precision?" is a query, not a guess.

Muscle hierarchy

The vocabulary is ordered from broad group to increasingly precise muscle and, where useful, head or subdivision. A value at any leaf therefore also belongs to every node above it — for example, Triceps long headTriceps brachiiTriceps (group).

flowchart LR
  %% Read from left to right: group → muscle → head / subdivision.
  chest[Chest] --> pmajor[Pectoralis major]
  chest --> pminor[Pectoralis minor]
  chest --> serratus[Serratus anterior]
  pmajor --> clavicular["Upper chest (clavicular)"]
  pmajor --> sternocostal["Mid/lower chest (sternocostal)"]

  back[Back] --> lats[Latissimus dorsi]
  back --> traps[Trapezius]
  back --> rhomboids[Rhomboids]
  back --> teres[Teres major]
  traps --> upperTraps[Upper traps]
  traps --> middleTraps[Middle traps]
  traps --> lowerTraps[Lower traps]

  lowerBack[Lower back] --> erectors[Erector spinae]
  lowerBack --> quadratus[Quadratus lumborum]

  shoulders[Shoulders] --> deltoid[Deltoid]
  shoulders --> cuff[Rotator cuff]
  deltoid --> frontDelt[Front delt]
  deltoid --> sideDelt[Side delt]
  deltoid --> rearDelt[Rear delt]

  biceps[Biceps] --> bicepsBrachii[Biceps brachii]
  biceps --> brachialis[Brachialis]
  bicepsBrachii --> bicepsLong[Biceps long head]
  bicepsBrachii --> bicepsShort[Biceps short head]

  triceps[Triceps] --> tricepsBrachii[Triceps brachii]
  tricepsBrachii --> tricepsLong[Triceps long head]
  tricepsBrachii --> tricepsLateral[Triceps lateral head]
  tricepsBrachii --> tricepsMedial[Triceps medial head]

  forearms[Forearms] --> brachioradialis[Brachioradialis]
  forearms --> flexors[Wrist flexors]
  forearms --> extensors[Wrist extensors]

  core[Core] --> rectus[Rectus abdominis]
  core --> obliques[Obliques]
  core --> transversus[Transversus abdominis]
  core --> diaphragm[Diaphragm]
  core --> hipFlexors["Hip flexors (iliopsoas)"]
  obliques --> externalObliques[External obliques]
  obliques --> internalObliques[Internal obliques]

  glutes[Glutes] --> gluteMax[Gluteus maximus]
  glutes --> gluteMed[Gluteus medius]
  glutes --> gluteMin[Gluteus minimus]

  quads[Quadriceps] --> quadriceps[Quadriceps]
  quadriceps --> rectusFemoris[Rectus femoris]
  quadriceps --> vastusLateral[Vastus lateralis]
  quadriceps --> vastusMedial[Vastus medialis]
  quadriceps --> vastusIntermedius[Vastus intermedius]

  hamstrings[Hamstrings] --> hamstringComplex[Hamstrings]
  hamstringComplex --> bicepsFemoris[Biceps femoris]
  hamstringComplex --> semitendinosus[Semitendinosus]
  hamstringComplex --> semimembranosus[Semimembranosus]

  adductors[Adductors] --> hipAdductors[Hip adductors]

  calves[Calves] --> gastrocnemius[Gastrocnemius]
  calves --> soleus[Soleus]
  calves --> tibialis[Tibialis anterior]

  neck[Neck] --> neckFlexors[Neck flexors]
  neck --> neckExtensors[Neck extensors]

  classDef group fill:#1d4ed8,color:#fff,stroke:#1e3a8a,stroke-width:2px
  classDef muscle fill:#dbeafe,color:#172554,stroke:#60a5fa
  classDef head fill:#f0fdf4,color:#14532d,stroke:#86efac
  class chest,back,lowerBack,shoulders,biceps,triceps,forearms,core,glutes,quads,hamstrings,adductors,calves,neck group
  class pmajor,pminor,serratus,lats,traps,rhomboids,teres,erectors,quadratus,deltoid,cuff,bicepsBrachii,brachialis,tricepsBrachii,brachioradialis,flexors,extensors,rectus,obliques,transversus,diaphragm,hipFlexors,gluteMax,gluteMed,gluteMin,quadriceps,hamstringComplex,hipAdductors,gastrocnemius,soleus,tibialis,neckFlexors,neckExtensors muscle
  class clavicular,sternocostal,upperTraps,middleTraps,lowerTraps,frontDelt,sideDelt,rearDelt,bicepsLong,bicepsShort,tricepsLong,tricepsLateral,tricepsMedial,externalObliques,internalObliques,rectusFemoris,vastusLateral,vastusMedial,vastusIntermedius,bicepsFemoris,semitendinosus,semimembranosus head

Orthogonal axes instead of one overloaded category. modality (what it is) · usage_tags (what it is used for, multi-valued) · mechanic · force_vector · movement_pattern · laterality · tracking_type (how it is logged) — each from a closed vocabulary.

Equipment split into two questions. primary_equipment is the one thing that creates the load. setup is everything else that has to be standing there. That split is what makes "what can I do in a hotel room?" answerable: primary_equipment: bodyweight and setup: [].

Text is separate from facts, in any number of languages. No name_en column exists anywhere. A new language is one entry in vocab/languages.yaml plus a directory — no schema change, no build change. Translators never touch anatomy; data curators never touch prose.

Identifiers are a contract. Consuming apps store exercise IDs in user workout logs. Nothing is ever hard deleted; merges go through a shipped alias table so downstream apps can migrate user data safely. See SCHEMA.md §3.

Provenance is recorded per field. Whether a value came from upstream, from a human, or from a model — with which model and reviewed by whom. Machine assistance is used heavily and said out loud, and every generated value is gated by CI invariants and human review.

Repository layout

data/exercises/<id>.yaml      Language-neutral facts, one file per exercise
data/i18n/<lang>/<id>.yaml    Text, one file per exercise per language
vocab/                        Closed vocabularies: muscles, equipment, classification, languages, licenses
schema/                       JSON Schemas + the CI invariants
snapshot/                     The frozen upstream snapshot the import was built from
oedb/                         Shared library used by the import, build and validator
build/                        YAML -> SQLite + manifest + reports
import/                       One-time upstream importer
test/                         Acceptance and rule tests; test/golden/ is the phase 2 eval set
reports/                      Generated review reports: outliers, name changes, language checks

Where it stands

909 exercises   868 active · 15 merged · 26 deprecated
                868 of 868 active exercises fully classified
LanguageNamesDescriptions
English868868
German868868
French868868
Italian868868
Japanese868868
Spanish644644

English, German, French, Italian, and Japanese are complete across all 868 active exercises. Spanish covers 644 active exercises. Seventeen further languages carry partial upstream text (23 languages total). They are shipped as they are and marked accordingly; none of them is claimed to be complete.

Building it yourself

pip install -r requirements.txt
python3 build/validate.py                 # the invariants from schema/invariants.md
python3 build/build_db.py --db-out artifacts/catalog.db
python3 build/check_database.py artifacts/catalog.db

Nothing there touches the network. Refreshing from upstream is a separate, deliberate step that lands in the repository as a reviewable snapshot commit:

python3 import/fetch_wger_snapshot.py
python3 import/wger_to_yaml.py

SCHEMA.md is the specification. Read it before contributing.

Using the database

Each release publishes a SQLite file, a JSON manifest with a SHA-256 checksum, and a diff report against the previous release. Point your app at the manifest, verify the checksum, and read the database directly.

Releases carry two independent version numbers: version for content and schema_version for structure. Check schema_version before consuming a release so a structural change can never break an older client.

Projects using OpenExerciseDB

  • TrainLibre — an independent personal fitness app that uses OpenExerciseDB as an exercise-data source.

Contributing

Corrections are welcome, especially to muscle assignments — that is the weakest part of the inherited data and the main reason this fork exists.

  1. Edit the relevant data/exercises/<id>.yaml or data/i18n/<lang>/<id>.yaml.
  2. Use only values from vocab/. CI rejects anything else.
  3. Open a pull request. The invariants in schema/invariants.md run automatically.

Do not edit id or slug — see SCHEMA.md §3 for why.

Roadmap

License

Data is CC BY-SA 4.0, the build tooling is MIT. Upstream records keep their original per-entry license and author. See LICENSE.md and ATTRIBUTION.md.