Open-source project management: issues, cycles, modules and a roadmap, with a hosted plan and a self-hosted community edition of the same application.
Build me the issue tracker I actually need instead of a hosted Plane: issues, cycles and a roadmap, sized for the team that will use it. Read this first: Plane is open source and self-hosting it is a real answer — the cloud plan buys upgrades and backups. Build this when you want the model to fit how your team actually works, because the reason people bounce between trackers is never the features, it is that somebody else's model does not fit. STACK - Node 20+ with Fastify, server-rendered HTML with a little vanilla JS - SQLite through better-sqlite3, WAL mode, with FTS5 - Caddy in front THE DATA MODEL - projects: id, key, name, description, lead_id, is_archived — the key is the prefix in every issue number - issues: id, project_id, number, title, description_md, state_id, priority, assignee_id, parent_id, estimate, start_date, target_date, created_by, created_at, updated_at, completed_at, archived_at - states: id, project_id, name, group, position — the group is one of backlog, unstarted, started, completed, cancelled, and every report depends on it. Custom names, fixed groups - cycles: id, project_id, name, starts_on, ends_on, is_active; cycle_issues: cycle_id, issue_id, added_at, removed_at - modules: id, project_id, name, target_date, lead_id; module_issues - labels, issue_labels, comments, attachments, subscribers - issue_activity: id, issue_id, field, old_value, new_value, actor_id, at — append-only, and the whole history of an issue - links: id, issue_id, kind, target_issue_id — blocks, blocked by, relates to, duplicates - Issue numbers per project, allocated in the transaction that creates the issue, never reused. PROJ-142 is a permanent name that goes in commit messages and stays there forever STATES AND WHY THE GROUP MATTERS - Teams want their own state names. Reports need to know what a state means - So a state has a free name and a fixed group. 'In review' and 'QA' are both started; the burndown does not care what you called them - Moving an issue into a completed-group state stamps completed_at, which is what every cycle report is computed from CYCLES - A fixed period with a set of issues. Adding and removing is recorded with a timestamp, which is what makes scope change visible rather than invisible - A burndown computed from the activity log at query time: what was in the cycle each day, and how much was done. Never a stored daily snapshot - Scope added mid-cycle shown as a separate line. A burndown that hides added work is a burndown that lies - Issues not finished are carried forward explicitly, with the carry recorded — an issue carried three times is telling you something MODULES AND THE ROADMAP - A module is a body of work with a target date, spanning cycles - The roadmap is modules on a timeline with progress computed from their issues - Progress is issues completed over issues total, or estimate completed over estimate total, chosen per project and stated on the page VIEWS - List, board grouped by state or assignee or priority, calendar on dates, and a spreadsheet-like table - Filters composable, and a view is a saved filter, shareable by URL - Every view respects permissions inside the query rather than filtering afterwards WRITING AN ISSUE - Title and description in Markdown with a live editor - Sub-issues with a parent, one level of nesting, because deeper is where trackers become unusable - Relations: blocks, blocked by, relates to, duplicates, each recorded once and shown from both sides - Attachments stored by hash with the type from content - Comments with mentions that notify, and an activity feed interleaved with them so the whole history reads in order GIT INTEGRATION, WHICH IS WHAT MAKES IT PART OF THE WORK - A commit or branch mentioning the issue key links to it, through a webhook from the forge with signature verification - A merged pull request moves the issue to a configured state - The links are recorded on the issue, so 'what changed for this' is answerable from the issue itself - Never write to the repository. Read the events and record them SEARCH AND SPEED - FTS5 over titles, descriptions and comments, with filters - Keyboard for everything: create, assign, change state, comment, search. A tracker is used all day, and the mouse is the slow part - The list must be fast with fifty thousand issues, which means indexes chosen deliberately and no unbounded query NOTIFICATIONS - Subscribe to an issue automatically when you comment or are assigned, with a way out - Batched by default: one digest rather than eleven emails. An over-notifying tracker gets filtered to a folder nobody opens - Mentions notify immediately, because that is the one case where it matters OPERATIONS - .env: DATABASE_PATH, STORAGE_PATH, BASE_URL, SESSION_SECRET, OIDC_*, SMTP_URL, FORGE_WEBHOOK_SECRET - Migrations on boot, each once - Nightly backup off the machine, restore script - Health endpoint WHAT MATTERS MOST The activity log and state groups. Build append-only activity and the fixed groups first — every report you will ever want is derived from those two, and neither can be reconstructed later. Then make the keyboard path from 'idea' to 'issue assigned' take under ten seconds. Give me the repository, migrations, .env.example, a seed project with two cycles, and a README with deploy steps behind Caddy.
What you lose
- A managed instance with upgrades and backups, which is what the cloud plan buys
- Cycles, modules and a roadmap already modelled, which is more design work than it looks
- Integrations with git providers and chat already written
If you would rather not build
- GitHub Projects, which is free
What it costs
read from their page 15 Aug 2026
| Plan | Billed monthly | Billed yearly | Last read |
|---|---|---|---|
| — | $6/mo | — | 15 Aug 2026 |
Their pricing page is where these came from. Seeing a different price? Tell us.
The escape hatch
open source · no votes, no paid placement
Vikunja
$0A smaller self-hosted tracker with boards, lists and a Gantt view.
go-vikunja/vikunjafree · open source
Why this verdict
our own opinion · changed only by a person
77/100
Verdict yes at 77 because the code is already free. The advice worth taking is to keep the model small and put every change in a history table.
History
tracked since 10 Aug 2026 · nothing is ever overwritten
Questions about Plane
answered from the record above
Is Plane free?
No — the plan we track is $6 a month. Pro at $6 per seat per month; the community edition is free to self-host.
Can you replace Plane by building your own?
YES. Replaceable in one session with an AI coding agent. Replacement score 77 out of 100, build time one session. Read what you lose before you decide.
How much does Plane cost?
$6 a month on Pro — $72 a year. Recorded 14 Aug 2026.
What do you lose by replacing Plane?
A managed instance with upgrades and backups, which is what the cloud plan buys; Cycles, modules and a roadmap already modelled, which is more design work than it looks; Integrations with git providers and chat already written. If any of those carry weight for you, keep paying.
Is there an open-source alternative to Plane?
Yes: Plane, Vikunja. The prompt on this page is for when you want it your way instead.
Related entries
same category first, most replaced first
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

