Plane

plane.socontributed by Samuele Ongaro

YES

Replaceable in one session with an AI coding agent.

Open-source project management: issues, cycles, modules and a roadmap, with a hosted plan and a self-hosted community edition of the same application.

Promptfree, for everyone, and the only version there is
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

PlanBilled monthlyBilled yearlyLast 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

Plane

$0

The product itself, self-hostable with Docker Compose.

makeplane/planefree · open source

Vikunja

$0

A 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

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

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

All 33 in Tasks & project management

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