Kimai

kimai.orgcontributed by Samuele Ongaro

YES

Replaceable in one session with an AI coding agent.

Open-source time tracking for teams and freelancers: projects, activities, rates, exports and invoicing, hosted by them or on your own server.

Promptfree, for everyone, and the only version there is
Build me the time tracking I actually need instead of a hosted Kimai: projects, activities, rates, exports and an invoice at the end.

Read this first: Kimai is open source and self-hosting it costs nothing but a container — the fee buys a hosted instance kept updated, and country-specific export templates. Build this when you want the data model to fit exactly how you bill, which is usually the reason people leave a general tracker.

STACK
- Node 20+ with Fastify, server-rendered HTML with a little vanilla JS
- SQLite through better-sqlite3, WAL mode
- Caddy in front

THE DATA MODEL
- customers: id, name, address, vat_number, currency, timezone, hourly_cents, archived_at
- projects: id, customer_id, name, order_number, budget_cents, budget_hours, budget_is_recurring, starts_on, ends_on, hourly_cents, archived_at
- activities: id, project_id, name, hourly_cents, is_billable, archived_at — an activity may be global or belong to one project
- users: id, email, name, hourly_cents, internal_cost_cents, is_active, role
- rates: id, scope, scope_id, user_id, hourly_cents, currency, effective_from — the rate in force when the work happened is the rate that bills, always
- timesheets: id, user_id, activity_id, project_id, description, started_at, ended_at, duration_seconds, is_billable, is_exported, is_locked, invoice_id, tags_json, fixed_rate_cents, hourly_rate_cents, source
- timesheet_revisions: id, timesheet_id, field, old_value, new_value, changed_by, at — append-only
- Rate resolution order stated once and implemented once: timesheet override, then user on activity, then activity, then user on project, then project, then customer, then user, then a default. Write it down, test it, and never scatter it through the code

TIME
- A record is two instants; the duration is derived. Never store a duration alone
- One running timer per user, enforced with a partial unique index
- Manual entries and timer entries are the same row with a different source
- A timer running past a threshold is flagged and offered for trimming, never trimmed silently
- Rounding is applied when exporting or invoicing, never on save. The raw seconds are the record
- Every instant UTC, displayed in the user's own zone

BILLABLE AND COST
- A user has a billing rate and an internal cost. The gap is the margin, and a tracker that only knows one of the two cannot say whether the work was worth doing
- Fixed-rate entries for work billed as a lump, alongside hourly ones
- Non-billable time tracked as carefully as billable, because that is where a month actually goes

BUDGETS
- Money or hours, per project or per activity, one-off or recurring monthly
- Progress visible wherever the project appears, not only in a report
- A projection: at the current rate the budget runs out on this date
- Alerts at thresholds to the project's owner, once per threshold per period

REPORTS AND EXPORTS
- Group by customer, project, activity, user, day, week or month, and filter by all of them
- Everything computed from rows at query time. No stored totals, ever
- Export CSV, XLSX and a PDF timesheet for a client, each from a template that can be edited without touching code
- A template is a file with placeholders. That is the whole extension mechanism, and it covers most of what a plugin system is asked for

INVOICING
- Select unexported, unlocked, billable entries for a period and issue an invoice from them
- Numbering from a sequence table, per year, allocated inside the issuing transaction, gapless
- The invoice is immutable once issued; a correction is a credit note referencing it
- Entries marked exported and locked, so nothing bills twice
- The PDF generated once and stored with its hash

APPROVAL AND LOCKING
- Submit a period, a reviewer approves or returns it with a note
- Approved periods lock; an entry inside one cannot change without an explicit, logged unlock
- This is what makes the hours usable for payroll or for a client dispute, and it is what homemade trackers never build

TEAMS AND PERMISSIONS
- Roles: user, team lead, administrator
- A user sees their own entries; a lead sees their team's; an administrator sees everything
- Enforced on the server for every query, default deny

THE API
- REST for timesheets, projects, activities and customers, with tokens and scopes
- A start and stop endpoint, so a shell script or a keyboard shortcut can drive it
- Webhooks on entry created and updated

OPERATIONS
- .env: DATABASE_PATH, BASE_URL, SESSION_SECRET, SMTP_URL
- Migrations on boot, each once
- Nightly backup off the machine, restore script
- Health endpoint

WHAT MATTERS MOST
Rate resolution and locking. Write the resolution order as one function with tests before anything is visible, then change a rate in the middle of a month and confirm last month's report did not move. Hours are what people are paid from, and a tracker that silently restates history is trusted exactly once.

Give me the repository, migrations, .env.example, a seed with two customers and a month of work, an export template, and a README with deploy steps behind Caddy.

What you lose

  • A hosted instance kept updated and backed up
  • Exports and invoice templates already built for several countries
  • A plugin system covering the odd requirement you have not thought of yet

If you would rather not build

  • Toggl Track, for polish
  • A CSV and a script, which is genuinely enough for one person

What it costs

as published on their pricing page

PlanBilled monthlyBilled yearlyLast read
—$6/mo——

Their pricing page is where these came from. Seeing a different price? Tell us.

The escape hatch

open source · no votes, no paid placement

Kimai

$0

The product itself, free to self-host with Docker.

kimai/kimaifree · open source

ActivityWatch

$0

Automatic activity recording, if you would rather not start timers.

ActivityWatch/activitywatchfree · open source

Why this verdict

our own opinion · changed only by a person

85/100

Verdict yes at 85. A timer is a start and an end. Keeping exact times and rounding only on the invoice is the rule that saves you later.

History

tracked since 10 Aug 2026 · nothing is ever overwritten

Interest · last 30 dayspeak 1/day
views0130 Aug4 Sept9 Sept14 Sept19 Sept24 Sept28 Sept
— views— prompt copies none yet— votes none yet

Questions about Kimai

answered from the record above

Is Kimai free?

No — the plan we track is $6 a month. Cloud from around €6 per user per month; the software is free to self-host.

Can you replace Kimai by building your own?

YES. Replaceable in one session with an AI coding agent. Replacement score 85 out of 100, build time one session. Read what you lose before you decide.

How much does Kimai cost?

$6 a month on Cloud — $72 a year. Recorded 10 Aug 2026.

What do you lose by replacing Kimai?

A hosted instance kept updated and backed up; Exports and invoice templates already built for several countries; A plugin system covering the odd requirement you have not thought of yet. If any of those carry weight for you, keep paying.

Is there an open-source alternative to Kimai?

Yes: Kimai, ActivityWatch. The prompt on this page is for when you want it your way instead.

Related entries

same category first, most replaced first

All 18 in Time tracking & invoicing

Not sending yet

Every week, something stops being worth paying for.

New verdicts, prices that moved, entries added. One email a week. Unsubscribe in one click. Nothing is being sent yet — your address is kept here, and the first issue is the first thing it is used for.

free forever · no tracking pixel · stored here, never passed to anyone

Esc