GraFIT
Loads Garmin FIT files into a SQLite database and visualizes them in Grafana.
GraFIT parses .fit files (activities, sleep, GPS, etc.) using python-fitparse, writes them to SQLite using a schema generated from the FIT profile, and ships with Grafana provisioning (datasource + dashboards) so you can browse the data immediately.
Install
uv tool install grafit
Or run without installing:
uvx grafit <command> [options]
Requires Python 3.11+.
Usage
uv run grafit <command> [options]
Commands
init <db_path>— create and initialize the SQLite database.import <path> <db_path>— import a FIT file or directory of FIT files into the database.--forcereimport files already present in the database.--no-recursivedo not recurse into subdirectories.--fetch-weatherlook up historical hourly weather (temperature, apparent temperature, humidity) for each session's start coordinates and date from the Open-Meteo archive. Failures are logged and skipped — the FIT import itself never fails because of weather.
backfill-weather <db_path>— fetch weather for sessions already imported without--fetch-weather. Safe to re-run: only sessions missing weather are queried; rate-limited or failed sessions are picked up on the next run.--forcere-fetch weather even for sessions that already have it.
stats <db_path>— show row counts per table.purge <db_path> --file-hash <sha256>— remove all rows imported from a given file.generate-schema <output>— write the full DDL SQL to a file.install-provisioning <dest>— copy the bundled Grafana provisioning (datasource + dashboards) to a directory.--forceoverwrite the destination if it exists.
demo-data <dest>— generate a synthetic Garmin FIT tree (see Demo data).--daysdays of history (default 365),--end-date YYYY-MM-DDlast day (default yesterday),--seedrandom seed,--forcewrite into a non-empty directory.
demo-weather <db_path>— fillweather_hourlywith modelled Los Angeles weather for demo data, without calling Open-Meteo.
Global flag: -v / --verbose for debug logging.
Upgrading
The schema is generated from the FIT profile, so upgrading GraFIT (or its python-fitparse dependency) can add new fields. On the next import/init, missing columns are added to existing tables automatically (you'll see a Schema: added N new column(s) notice). New columns are NULL for already-imported rows — to backfill history, re-import the affected files with --force or rebuild the database from your FIT source.
Grafana
A docker-compose.yml is provided to run Grafana with the SQLite datasource plugin against ./fit_data.db and the bundled dashboards mounted from ./grafana-provisioning.
Note: the bundled compose file enables anonymous admin access and disables the login form. It is intended for local use only — do not expose it to a network.
Drop your FIT files into ./GARMIN and bring it up:
docker compose up
A grafit-init container installs the bundled provisioning, runs grafit init, and runs grafit import ./GARMIN against shared volumes; Grafana waits for it to finish before starting. Re-running docker compose up reuses the database — already-imported files are skipped by hash.
Grafana is then available at http://localhost:3000.
Demo data
For demo/testing purposes, GraFIT can generate a synthetic dataset for a fictional Los Angeles athlete — a year of activities, sleep, stress, body battery, HRV, SpO2, saved locations etc:
docker compose -f docker-compose.demo.yml up
That generates the FIT files into their own volume, imports them into a separate database and starts Grafana on http://localhost:3000 with everything populated. Set GRAFIT_DEMO_DAYS=90 to generate less history — a year takes a couple of minutes and about 300 MB of database, 90 days about 77 MB.
Demo route geometry © OpenStreetMap contributors (ODbL), elevations from Open-Meteo (Copernicus DEM GLO-90).
Release files for grafit 1.41.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| grafit-1.41.1.tar.gz | 69.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| grafit-1.41.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 152.0 kB
Release files / grafit-1.41.1.tar.gz
| Download URL | grafit-1.41.1.tar.gz |
|---|---|
| Size | 69.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1bdc905eeac1c627fd71be0a516f9921428ff9a26dddb54c7b18102f5ec8535a
|
|
BLAKE2b-256 checksum How to use checksums |
2d77f2d4ca89bb169207c498a0fa44c040f94b3bb1af36043e099a4a661bd783
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"10","id":"buster","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / grafit-1.41.1-py3-none-any.whl
| Download URL | grafit-1.41.1-py3-none-any.whl |
|---|---|
| Size | 82.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
be2e9ebd24e577e77606755acd76172f7a7012a03fc69207afb183084a89239a
|
|
BLAKE2b-256 checksum How to use checksums |
d5e74236de28d59eac8ef64f50a772d911f225214e81a902d18328dd0dc6b154
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"10","id":"buster","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|