A small, self-hosted time-tracking web app. Log hours per client, task type and period, track daily-hours targets and overtime, and produce printable per-client and per-period reports.
It ships as a single Go binary with server-side rendered
templ views, a Bulma UI, and an
embedded SQLite database. Static assets and templates are compiled into the
binary, so a deployment is one file. That same binary runs the web server
(time-tracker serve) and the admin commands (register, export-users).
- Tasks: log time entries with a title, client, task type, period, date and hours. Entries are grouped by day with per-day totals.
- Clients, task types and periods: manage each from its own page, with dedicated edit pages to rename them. A client can restrict which task types it allows, and one period can be marked as the default.
- Daily targets and overtime: set target hours per weekday under My account. The Time page shows each day's hours against its target, grouped by month with monthly subtotals.
- Date-range filter: sum hours, target and overtime between two dates. An open-ended range runs up to today.
- Printable reports: standalone, print-friendly pages that open the browser
print dialog for save-as-PDF.
/time/reportproduces a day-by-day time report over the selected range./clients/{id}/reportproduces a per-client report: a summary table of hours per task type, followed by one detail table per task type, honoring the active filters.
- Bilingual: English and French (
/lang/en,/lang/fr). - Authentication: email and password login backed by opaque, server-side session tokens stored in a cookie. Sessions live in memory, so they are lost on restart and can be revoked instantly.
Choose one of the options below, then follow First run to create a user and log in.
A multi-arch image is published to GHCR on every push to master and on
version tags, for linux/amd64, linux/arm64, linux/arm/v7, linux/arm/v6,
linux/386, linux/ppc64le, linux/s390x and linux/riscv64.
docker run -d -p 8080:8080 \
-e TRACKER_JWT_SECRET=change-me \
-e TRACKER_SECURE_COOKIES=false \
-v time-tracker-data:/data \
ghcr.io/bloomyindev/time-tracker:latestThe container runs time-tracker serve by default. The database is stored in
the /data volume (TRACKER_DB_PATH=/data/time-tracker.db). Run admin commands inside
the container with docker exec <container> /app/time-tracker <command> (see
CLI).
An example compose.yml is included:
docker compose up -d
docker compose exec time-tracker /app/time-tracker register \
--email you@example.com --password secretDownload a tarball for your OS and architecture from the
Releases page. Each
archive contains the single time-tracker binary. Prebuilt targets:
| OS | Architectures |
|---|---|
| Linux | amd64, 386, arm64, armv7, ppc64le, riscv64, s390x, loong64 |
| macOS | amd64, arm64 |
| Windows | amd64, 386, arm64 |
| FreeBSD | amd64, arm64 |
| OpenBSD | amd64, arm64 |
| NetBSD | amd64 |
tar -xzf time-tracker_*_linux_amd64.tar.gz
cd time-tracker_*_linux_amd64
TRACKER_JWT_SECRET=change-me TRACKER_SECURE_COOKIES=false ./time-tracker serveBuilding from source requires Go 1.26 or later. See DEVELOPMENT.md for the full setup.
- Start the server. It listens on http://localhost:8080. In production,
always set
TRACKER_JWT_SECRET(see Configuration). - Create a user. There is no public sign-up:
./time-tracker register --email you@example.com --password secret # from source: ./bin/time-tracker register ... # docker: docker exec <container> /app/time-tracker register ...
- Log in at http://localhost:8080/login with those credentials.
The app is configured through environment variables:
| Variable | Default | Description |
|---|---|---|
TRACKER_PORT |
8080 |
TCP port the server listens on. |
TRACKER_DB_PATH |
time-tracker.db |
Path to the SQLite database file. |
TRACKER_JWT_SECRET |
dev-secret-change-me |
Secret for signing JWTs used by the (currently unused) bearer-token API flow. Set this in production. |
TRACKER_SECURE_COOKIES |
true |
Mark cookies Secure, so browsers only send them over HTTPS. Set to false to serve plain HTTP. |
TRACKER_SQLITE_WAL |
false |
Enable SQLite write-ahead logging. Adds -wal and -shm files next to the database. |
Serving over plain HTTP? Set TRACKER_SECURE_COOKIES=false. The default
assumes a TLS-terminating reverse proxy in front. Left on over plain HTTP, the
browser accepts the session cookie and then never sends it back, so logging in
appears to do nothing.
The database path can also be passed with --db-path, which takes precedence
over the environment. Migrations are embedded in the binary and applied on startup;
each one is recorded in a schema_migrations table so it runs exactly once.
The admin commands live in the same binary as the server:
time-tracker serve # run the web server
time-tracker register --email <email> --password <password> # create a user
time-tracker export-users # dump users as JSON (no password hashes)Every command accepts --db-path (or the TRACKER_DB_PATH environment variable).
Development setup, build instructions and the project layout are documented in DEVELOPMENT.md.
GNU AGPL v3. See LICENSE.