The short answer
Pick Plane for a development team that works in sprints and wants a fast, modern tool: boards, cycles with a burndown chart, sub-items and blocking links are all in its free Community Edition, and it ran in about 1 GB. Pick OpenProject for classic project management: Gantt charts with dependencies, time tracking with reports, custom fields, workflows per role, a backlog with sprints and a Swedish interface are all free, and it has a free Jira importer, but it used about 1.6 GB and feels heavier.
Neither imports from Jira Cloud in its free version. Plane's Community Edition has no time tracking, custom fields or work item types; OpenProject keeps single sign-on with OpenID Connect or SAML for its paid plans.
What we tested
We installed both on the same fresh Melonslab VC-P Alloy (2 vCPU, 8 GB) with Debian 13, each under a user of its own, behind the same Caddy. Plane followed our guide Plane with rootless Podman step by step, and every step worked as written. We have no OpenProject guide, so we ran OpenProject's official image in the same pattern: a pod under its own user, Quadlet units, passwords as Podman secrets and our Caddy in front (How we ran OpenProject has the files).
Then we built the same project in both, a web shop relaunch:
- 30 work items: 2 epics, 9 stories, 13 tasks and 6 bugs, with priorities from highest to lowest, 25 of them assigned, 4 labels (
backend,frontend,payments,ux) and states from to-do to done; - a two-week sprint, Sprint 1, with 11 of the items, and a board;
- 18 items under a parent, five of them two levels deep, and "blocks" links between items;
- 11.75 hours of logged time on five items, four comments, and a PNG and a PDF attached;
- two users: Anna, who runs the project, and Erik, an ordinary member.
We built both through their APIs and then checked each view in a browser. We also imported a Jira project, set up email to a local test mail server, switched the interface to Swedish, rebooted the server, and measured memory at rest and while Anna and Erik worked.
Jira itself was not tested. We did not sign up for Jira. What this page says about it comes from Atlassian's own pages, linked where we use them and read on 14 October 2026.
The numbers
| Plane 1.4.2 | OpenProject 17.9.1 | |
|---|---|---|
| Containers | 13: web app, admin, public pages, live server, API, two workers, a one-off database job, PostgreSQL 15, Valkey, RabbitMQ, Garage for files, Plane's proxy | 2: OpenProject (web server, background worker, cache and live server in one), PostgreSQL 17 |
| Memory at rest after a reboot | about 1.0 GB (API 268 MB, worker 236, scheduler 145, live server 136) | about 1.63 GB (OpenProject 1.61 GB, PostgreSQL 25 MB) |
| Memory at the peak of use | about 1.06 GB | about 2.71 GB |
| Images on disk | 3.07 GB | 2.59 GB |
| Data after the test | 78 MB | 86 MB |
From useradd to the login page | about 9 minutes 20 seconds | about 4 minutes 20 seconds |
| Back after a reboot | 3 minutes | 3 minutes 40 seconds |
| Sprints and backlog | cycles, with burndown | backlog with sprints, story points, sprint board, burndown |
| Gantt with dependencies | timeline; dependencies need Pro | yes |
| Time tracking | needs Pro | yes, with reports |
| Custom fields, work item types | need Pro | yes |
| Jira import, free | no | yes, from Jira Data Center 10 and 11 |
| Single sign-on, free | Google, GitHub, GitLab, Gitea | LDAP; OpenID Connect and SAML need Enterprise |
| Swedish interface | no | yes |
| Licence | AGPL 3.0 | GPL 3.0 |
Memory is the sum of each app's containers, measured with podman stats from four to eight minutes after a reboot; it stayed within 10 MB over that time. The peak is the highest reading while Anna and Erik listed, opened, changed and commented on work items through each app's API for three minutes, two users sending up to five requests a second between them. The setup time is how long the commands took to run, mostly downloading images and setting up the database, not the time you need to read and type them.
Setup
Plane is the bigger setup: 13 units and Garage for attachments, which our guide walks through. Starting it took about 9 minutes 20 seconds from useradd, most of it downloading 2.7 GB of compressed images (3.07 GB once unpacked on disk) and Plane setting up its database. The first person to open /god-mode/ becomes the instance admin, so the guide sets that up right away, closes sign-ups and switches off the usage data Plane sends by default.
OpenProject ships an all-in-one image with its own PostgreSQL inside. We ran that image with a separate PostgreSQL container instead, so the database version and its backups are ours, and an update of OpenProject never touches the database engine. That makes two containers. The first start sets up the database, an admin account and a demo project. From useradd to the login page took about 4 minutes 20 seconds, about three of them that first start.
Day-to-day use
Plane is fast and simple. A project shows its work items as a list, a board, a calendar, a spreadsheet or a timeline, with a switch at the top. The board has a column per state, and you drag cards between them. Opening an item shows its description, sub-items, relations, attachments, comments and activity on one page. Plane numbers items per project, WEB-1, WEB-2, as Jira does.
OpenProject has more screens: a work package table, a Gantt chart, boards, the backlog, a calendar and time reports, each a module you switch on per project. New users get a guided tour, and a work package has many more fields than a Plane item. By default it numbers work packages across the whole instance, #98; under Administration > Work packages > Identifiers it can number them per project, WEBS-7, which its Jira importer requires. Switching changes the IDs of every work package on the server, and the old links keep working.
Boards, backlog and sprints
- Plane groups work into cycles. Our Sprint 1 showed its 11 items, how many were done and a burndown chart. Plane puts states in groups (backlog, unstarted, started, completed and cancelled), and the board follows them.
- OpenProject's Backlogs module showed an inbox of 18 items and Sprint 1 with its 11 items and story points per item, and each sprint has a burndown chart and a sprint board. Its Boards come in six kinds: basic, Kanban by status, by assignee, by version, by subproject and by parent. Our Kanban board started with only the New column; we added In progress with Add list to board, and the cards with that status appeared in it.
Both handled parent and child items. OpenProject refused one of our links: a task that blocks its own parent story, with "This relation would create a circular dependency." Plane accepted it, so Plane's copy has one "blocks" link more.
Gantt and timeline
We gave five items in both a start and an end date.
OpenProject drew them as a Gantt chart next to the work package table, and parents took their dates from their children: the epic, which had no dates, spanned 12 to 23 October, and a story we had given 12 to 23 October was cut to its two tasks' 12 to 16 October. Links of the kind "precedes" and "follows" are its dependencies; we linked two stories that way.
Plane's timeline showed the same five items as bars, with their length in days. The epic above them got no bar, as Plane does not add up dates from sub-items. Drawing dependencies between bars, "Dependencies in Timeline", is in its Pro plan, according to Plane's pricing page, read on 14 October 2026.
Time tracking
OpenProject logged our 11.75 hours on five items, by both users, and its Time and costs report grouped them by week and work package, with buttons to export to Excel and a PDF timesheet. Erik, as an ordinary member, could log time but not delete work packages.
Plane's Community Edition has no time tracking. Worklogs start at Pro, according to the pricing page, so our logged hours had nowhere to go in Plane.
Workflows and custom fields
Plane has states per project, in five fixed groups, and you can add more states to each group; labels are free. Work item types, custom properties and workflows with rules are paid: types and properties from Pro, workflows from Business.
OpenProject has types (seven out of the box, among them Epic, User story, Task and Bug), workflows that set which role may move a type from one status to another, and custom fields in many formats, all free. Jira's labels have no direct match: we made a custom field with several values for them. Custom action buttons, read-only states and arranging the form per type are in its Enterprise Basic plan.
Permissions
Both kept Erik in his place. As an ordinary member, he could not rename or delete the project, nor delete a work item, in either app; OpenProject let him log time.
- Plane has three roles, Admin, Member and Guest, in the workspace and in each project. Erik could invite a new person to the workspace as a member, and the invite was sent. Through the API, Plane silently dropped Erik as an assignee until we had added him to the project.
- OpenProject has roles you define per project, with a long list of permissions each. Out of the box there are Project admin, Member and Reader, plus roles for sharing single work packages.
Jira import
Both importers read from a running Jira over its API with a token, not from an export file. We did not have a real Jira, so we wrote a small test server that answers Jira Data Center 10.3's REST API with our 30 work items in Jira's own JSON format. This was constructed data, not a real Jira.
- Plane's Jira importer is in Plane Cloud and in its Commercial Edition, which is closed source, according to Plane's importer documentation. The Community Edition from our guide has no import page. Its CSV import is in the same editions. We did not test it.
- OpenProject's Jira Migrator, under Administration > Import, is free and marked beta. It connects to Jira Data Center 10 or 11 with a personal access token; according to its documentation, Jira Cloud is not supported. It refused to start until project-based identifiers were switched on, and it blocks Jira servers on private addresses unless you allow them in OpenProject's configuration, which we did for our test server.
From our constructed Jira, OpenProject imported all 30 issues with their types, statuses, priorities and estimates, matched both assignees to the Anna and Erik who already had accounts, and brought the four comments, both attachments and the descriptions, with Jira's markup turned into OpenProject's. It added the Jira types, statuses and priorities that OpenProject lacked, such as Story, To Do and Highest, and matched the rest, such as In progress. It did not bring the epic links and sub-task parents, the "blocks" links, the logged time, the sprint or the labels; its documentation lists relations and sprints as coming. Before you finalise an import, you can review it and undo it.
Coming from Jira Cloud, you have Plane's importer in Plane Cloud or its Commercial Edition, Atlassian's CSV export with your own script against either API, or a move by hand.
Email notifications
We pointed both at a local test mail server; sending through a real email provider was not tested.
- Plane emailed Erik about each of the 13 items assigned to him, one email per item, about five minutes later, and sent the invites.
- OpenProject emailed Erik within seconds when Anna mentioned him in a comment. Assignments and other changes go to its notification centre in the app, and by default each user also gets a daily email at 08:00 on weekdays about unread notifications, which we did not wait for. Both are set under Account settings > Notification and email.
API
Both have a full REST API with keys per user, which is how we built the test projects.
- Plane's API at
/api/v1/covers projects, work items, cycles, modules, labels, comments, links, relations and attachments. Keys are created per user and limited to 60 requests a minute. - OpenProject's API v3 at
/api/v3/covers work packages, relations, time entries, comments, attachments, users and memberships.
Sign-in and single sign-on
We tested passwords in both.
- Plane's Community Edition signs in with a password, a code by email, or Google, GitHub, GitLab or Gitea. OpenID Connect and SAML need its Commercial Edition with Pro, and LDAP its Enterprise plan, according to the pricing page.
- OpenProject Community has passwords, two-factor codes and LDAP sign-in for free. OpenID Connect and SAML single sign-on are in the Enterprise Professional plan, and syncing groups from LDAP in Premium, according to its Enterprise guide.
Swedish
OpenProject comes in Swedish: each user picks Svenska under Account settings > Account > Language, and Erik saw "Backlogg och sprintar", "Sök i OpenProject" and "Överordnad". Types, statuses and priorities are data created at setup, so ours stayed in English, as "User story", "New" and "High", because we set the server up in English. Plane has no Swedish; its 21 languages include German, French and Polish.
Resources
Plane is a Python API with two background workers, a Node.js live server and small containers for its web pages. At rest it used about 1.0 GB, most of it the API, the worker, the scheduler and the live server, and under our three minutes of use it rose only to about 1.06 GB, while answering 820 requests.
OpenProject is a Ruby on Rails app. Its container runs a web server with two workers, a background worker and a live-editing server, and those Ruby processes held most of its 1.61 GB at rest. PostgreSQL used 25 MB. Under the same three minutes it grew to 2.71 GB, and stayed at about 2.6 GB afterwards, since Ruby keeps the memory it has used. It also answered fewer of our requests in that time, 235 against Plane's 820, because each answer, such as a list of work packages with all their links, took longer.
Both fit an 8 GB server easily, together with room for more, as on our test server. OpenProject's own system requirements ask for 4 GB of memory for up to 200 users.
Updates and backups
Plane's guide pins its version, v1.4.2, and you update by changing the tag after reading the release notes, with a database job that runs before the API starts. Its backup is a database dump and Garage's two volumes, with Garage stopped for a few seconds. OpenProject's image follows the 17 tag in our setup, so minor and patch releases install by themselves through Podman's auto-update; a new major version is a tag you change. Its backup is a dump of PostgreSQL and the volume with attachments, taken while it runs: a few seconds and 4.3 MB in our test.
Both came back by themselves after a reboot, Plane in 3 minutes and OpenProject in 3 minutes 40 seconds.
How we ran OpenProject
OpenProject's Docker documentation offers two ways: an all-in-one image, or a Compose file with separate web, worker, cron, seeder, cache and proxy containers. We chose the all-in-one image with PostgreSQL in its own container, which OpenProject's database documentation allows with DATABASE_URL. It gives two containers instead of seven, and PostgreSQL stays ours to back up and upgrade. Two things we learned:
- If the database address in
DATABASE_URLis127.0.0.1, the image ignores it and starts its own PostgreSQL inside. Uselocalhost, which reaches the PostgreSQL container in the same pod. - PostgreSQL's first start, which sets up its files, took longer than systemd's 90 seconds while the server was busy, and systemd stopped it.
TimeoutStartSec=300gives it time.
As a user openproject, created like plane in step 1 of the Plane guide, create the secrets:
pw=$(openssl rand -hex 24)
printf %s "$pw" | podman secret create openproject-db-password -
printf %s "postgres://openproject:$pw@localhost:5432/openproject" | podman secret create openproject-db-url -
openssl rand -hex 64 | tr -d '\n' | podman secret create openproject-secret-key -
printf %s "$(openssl rand -base64 18)" | podman secret create openproject-admin-password -
printf %s 'your-smtp-password' | podman secret create openproject-smtp-password -
~/.config/containers/systemd/openproject.pod:
[Pod]
PodName=openproject
PublishPort=127.0.0.1:8193:80
[Install]
WantedBy=default.target
openproject-db.container:
[Container]
ContainerName=openproject-db
Image=docker.io/library/postgres:17-alpine
Pod=openproject.pod
Volume=openproject-db:/var/lib/postgresql/data
Environment=POSTGRES_USER=openproject POSTGRES_DB=openproject
Secret=openproject-db-password,type=env,target=POSTGRES_PASSWORD
HealthCmd=pg_isready -U openproject
HealthInterval=10s
Notify=healthy
AutoUpdate=registry
[Service]
Restart=always
TimeoutStartSec=300
openproject-app.container:
[Unit]
Requires=openproject-db.service
After=openproject-db.service
[Container]
ContainerName=openproject-app
Image=docker.io/openproject/openproject:17
Pod=openproject.pod
Volume=openproject-assets:/var/openproject/assets
Environment=OPENPROJECT_HOST__NAME=projects.example.com OPENPROJECT_HTTPS=true
Environment=OPENPROJECT_DEFAULT__LANGUAGE=en
Secret=openproject-db-url,type=env,target=DATABASE_URL
Secret=openproject-secret-key,type=env,target=SECRET_KEY_BASE
Secret=openproject-admin-password,type=env,target=OPENPROJECT_SEED__ADMIN__USER__PASSWORD
Environment=OPENPROJECT_SEED__ADMIN__USER__PASSWORD__RESET=false OPENPROJECT_SEED__ADMIN__USER__MAIL=admin@example.com
Environment=OPENPROJECT_EMAIL__DELIVERY__METHOD=smtp OPENPROJECT_SMTP__ADDRESS=smtp.example.com OPENPROJECT_SMTP__PORT=587
Environment=OPENPROJECT_SMTP__AUTHENTICATION=plain OPENPROJECT_SMTP__USER__NAME=openproject@example.com OPENPROJECT_SMTP__ENABLE__STARTTLS__AUTO=true
Secret=openproject-smtp-password,type=env,target=OPENPROJECT_SMTP__PASSWORD
Environment=OPENPROJECT_MAIL__FROM=openproject@example.com
AutoUpdate=registry
[Service]
Restart=always
TimeoutStartSec=900
Pull docker.io/openproject/openproject:17 and docker.io/library/postgres:17-alpine first, then run systemctl --user daemon-reload and systemctl --user start openproject-pod. It is ready when curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8193/health_checks/default prints 200. Sign in as admin with the password from podman secret inspect --showsecret openproject-admin-password. The block in Caddy's ~/Caddyfile:
projects.example.com {
reverse_proxy 127.0.0.1:8193
}
OPENPROJECT_DEFAULT__LANGUAGE is the language of the types, statuses and sample data created at the first start; we used en and did not try sv. To back up, run podman exec openproject-db pg_dump -U openproject openproject > openproject-db.sql and podman volume export openproject-assets > openproject-assets.tar, and keep the secrets. To restore, create the secrets from the backup, import the volume, start the pod so that PostgreSQL sets itself up, stop openproject-app, drop and create the openproject database, load the dump with psql and start openproject-app again. We did that for a newly created user, and the 30 work packages, the logged time, the comments and an attachment with the same checksum came back.
Licence and cost
We read the licence texts and pricing pages on 14 October 2026.
- Plane is made by Plane Software, Inc. in the United States. The Community Edition is open source under the AGPL 3.0, with no limit on users, and matches the Free plan of Plane Cloud, according to Plane's editions page. The paid plans need its closed-source Commercial Edition, which includes 12 free seats per workspace. The pricing page lists Pro at 6 US dollars per user a month billed yearly (8 monthly), with work item types, custom properties, worklogs, timeline dependencies and, self-hosted, OpenID Connect and SAML; and Business at 13 dollars (15 monthly), adding a workflow with rules and approvals of worklogs. Enterprise Grid, with LDAP, has no public price.
- OpenProject is made by OpenProject GmbH in Germany and is open source under the GPL 3.0. The Community edition has no user limit and includes everything this page calls free. Its on-premises Enterprise plans, on the pricing page, are Basic at 5.95 euros per user a month and Professional at 10.95, each for at least 25 users, Premium at 15.95 for at least 100, and Corporate on request from 250 users, for terms of one to five years. Basic adds custom actions, baseline comparisons, the team planner, placeholder users, read-only work packages, form configuration per type and more than one active sprint; Professional adds OpenID Connect and SAML, sharing work packages with outside users and internal comments; Premium adds LDAP group sync, portfolio and resource management. Boards, the backlog with sprints, Gantt charts, time tracking and the Jira Migrator all worked without a licence key in our test.
For a company running projects for its own staff, both free versions allow it at no cost, and on your own server the projects stay in Sweden.
Jira today
What follows is from Atlassian's own pages, read on 14 October 2026, not from our tests.
Jira Server is gone: Atlassian ended support for its Server products on 15 February 2024.
Jira Data Center, the edition you run yourself, is being retired as well. According to Atlassian's end-of-life page, which lists Jira Software Data Center among the products:
- new customers could no longer buy Data Center after 30 March 2026;
- existing customers can expand and upgrade until 30 March 2028, and renew up to the end date;
- on 28 March 2029 the subscriptions expire and the products become read-only, with no more support or security fixes.
That also limits OpenProject's importer, which reads only from Data Center: a Data Center customer has until then to move.
Jira Cloud, according to the pricing page, is free for up to 10 users with 2 GB of storage; Standard is listed at 8.48 US dollars and Premium at 15.56 per user a month, billed monthly; Enterprise is billed yearly only. Atlassian's plan comparison says Free has limits on permissions, roles and audit logs, Standard adds advanced permissions and audit logs, and single sign-on needs a separate Atlassian Guard subscription below Enterprise. Atlassian can keep Jira's data in the EU, in Frankfurt and Dublin, on Standard and up, according to its data residency page. Jira Cloud exports work items as CSV, up to 10,000 at a time, with each comment in a column of its own.
What you give up compared with Jira
Moving to your own server keeps your projects in Sweden, costs a fixed server price instead of a price per user, and nobody can retire your tool for you, as Atlassian is doing with Data Center. But be honest about what you leave behind:
- The migration. Neither free version imports from Jira Cloud. OpenProject's free importer works with Data Center, but in our test it left out epic links, sub-tasks, issue links, logged time, sprints and labels.
- The ecosystem. Jira's Marketplace apps, its automation rules and its integrations with Confluence, Bitbucket and other tools have no equal in either. Both have webhooks, and OpenProject has modules for GitHub and GitLab.
- One tool for both kinds of work. Jira does sprints and, on its higher plans, cross-team planning in one product. Here you pick: Plane for sprints, without time tracking or custom fields in its free version; OpenProject for plans and hours, with a heavier interface.
- AI. Jira's paid plans include Atlassian's Rovo AI, according to its pricing page. We did not test AI in either self-hosted tool.
- Running it. Updates, backups and the server are yours, and you need a working email account for invites and notifications.
Which one to pick
A development team working in sprints: Plane. It has the Jira-like feel: keys per project, a board per state, cycles with a burndown chart, sub-items, blocking links and a fast interface, in about 1 GB, with an open-source licence and no user limit. Its weak points are no time tracking, custom fields, work item types or timeline dependencies without the paid Commercial Edition, no Swedish, no free Jira import, 13 containers to run, and a member role that can invite people. Follow the Plane guide, on a VC-P Alloy.
Classic project management, with Gantt charts and hours: OpenProject. It plans with dates and dependencies, tracks time with reports, has a backlog with sprints, boards, custom fields and workflows, speaks Swedish and imports from Jira Data Center, all free. Its weak points are more memory, about 1.6 GB at rest, a busier interface, single sign-on with OpenID Connect or SAML only on its paid plans, a Jira importer still in beta that leaves out links, sprints and logged time, and no guide of ours yet: the files in How we ran OpenProject are what we ran, on top of the Podman guide. A VC-P Alloy suits it too.
Together they used about 2.6 GB at rest, so one VC-P Alloy runs both, as ours did.