Self-hosted service
plankanban/planka avatar
plankanban/planka

Planka: free self-hosted Kanban and the edges of the Community edition

Elegant open source project tracking. Self-hosted Kanban for teams — free Community edition, with PLANKA Pro for organisations.

12,682 stars1,403 forksJavaScriptNOASSERTION

At a glance

What is it?
PLANKA is a self-hosted Kanban board for teams that want their own PostgreSQL database, shipped as a Docker image listening on port 1337. The Community edition is free but skips mobile access, templates, guest roles and SSO, and the path to Pro is a one-way schema promote that only accepts certain releases.
Who is it for?
PLANKA suits a team that wants its board on its own PostgreSQL and accepts a fair-code licence plus a Community edition that stops at desktop web use.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 8 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • plankanban/planka12,682 ★ · +143
Star history
Repository2026-09-112026-11-14
plankanban/planka12.5k12.7k

143 Stars in the last 64 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The compose file ships SECRET_KEY=notsecretkey and warns on every start

The repository root carries a compose file that does most of the first install. It pulls ghcr.io/plankanban/planka:latest, mounts a named volume at /app/data, and publishes container port 1337 on host port 3000.

yaml
services:
  planka:
    image: ghcr.io/plankanban/planka:latest
    restart: on-failure
    volumes:
      - data:/app/data
    ports:
      - 3000:1337
    environment:
      - BASE_URL=http://localhost:3000
      - DATABASE_URL=postgresql://postgres@postgres/planka
      - SECRET_KEY=notsecretkey

DATABASE_URL assumes a Postgres host named postgres, which is a host you supply or change. SECRET_KEY matters more, and the file explains why in its own comment: every access token is signed with it, so leaving the published example value means anyone can mint a token for any account on the instance. The comment gives the fix, generate the value with openssl rand -hex 32, and states that PLANKA warns about this on every start until you change it. A second path exists for anyone who would rather not keep a key in the environment file: SECRET_KEY__FILE points at a mounted secret, and when you use it SECRET_KEY should not be set at all. DATABASE_URL has the same shape with DATABASE_PASSWORD__FILE, and the file also documents a commented override for the container user and group at 1000:1000 plus a tmpfs for /app/.tmp.

The Pro promote accepts 2.1.x and 2.2.x, and nothing runs backwards

Community and Pro are two editions of one installation, and moving between them is a migration rather than a swap of image tags. Pro upgrades an existing Community install in place, keeping the same database, volume and data. It adds a Valkey service and a one-off schema promote step. That promote is the sharp edge: it accepts only certain Community releases as a starting point, currently 2.1.x and 2.2.x, and from any other version it stops without changing anything.

What it cannot do is come back. The upgrade runs one way, with no downgrade to Community, so a team that tries it on production needs a backup or a copy first. The step by step guide lives in the customer center and only after you hold a key, and that guide is what lists the releases the promote accepts. A reader on an older Community version therefore finds out which versions qualify only after buying. The repository's most recent tags are v2.2.0 and v2.2.1, both from August 2026, and the last push to master landed on 2026-11-02, so the 2.2.x line the promote accepts is also the current one. That coincidence is convenient and temporary: a reader on 2.0.x has to move forward to 2.1.x or 2.2.x before any Pro migration can start.

Eight rows of the Community column are dashes

The edition comparison in the README is a table, and the dashes in the Community column are the part worth reading. Community ships boards, lists, cards, real time collaboration, markdown, attachments, comments, custom fields, stopwatch and due dates on cards, notifications through more than 100 providers, webhooks, a documented REST API, two factor authentication, and your own database and backups. It does not ship phones and tablets, five themes and an accent color, calendar, timeline, map and media views, recurring cards, card and board templates, one card on more than one board, guest roles, SSO over OIDC, PDF and HTML export, or support from the developers without a ticket queue.

Each of those removes something a particular team leans on. Field staff lose the phone layout and read the board in a desktop browser. A weekly standup card gets re-created by hand without recurring cards, and an on-call handover gets duplicated across boards without cross board cards. An external client needs a full account because guest roles are absent, and every account gets its own password because there is no SSO. The export row bites last: Community has no PDF or HTML export.

The difference in approach against a hosted board such as Trello sits in one line of the same table. PLANKA runs on your own Postgres and a named Docker volume, so the board keeps working without the vendor's servers. What you trade for that ownership is the Pro column.

fair-code splits the licence in two, and the description does not

The repository description calls PLANKA elegant open source project tracking. The licence section describes something narrower: fair code distributed under the Fair Use License and the PLANKA Pro/Enterprise License, held together by four named properties, source available, self hostable and extensible, plus enterprise licences available for additional features and support. Source is visible, and you may host and change it. The boundary is the split itself, between the Community licence and the commercial one, so a team planning a fork has to work out which licence its intended use falls under rather than assuming the words open source settle the question.

Two smaller facts sit nearby. Public support by email does not exist, GitHub is where requests go and Discord is the community channel. Security problems are the exception, and the README asks that they be emailed privately to [email protected] rather than filed as a public GitHub issue. A team that reports through the public issue tracker first publishes the details before anyone can pull a fix.

Six separate database scripts, and no documented order

The root package.json exposes the server database work as six scripts that each delegate into server/: server:db:init, server:db:migrate, server:db:upgrade, server:db:seed, server:db:create-admin-user and server:db:clean-orphaned-records.

bash
npm run server:db:init
npm run server:db:create-admin-user
npm run server:db:migrate

On a fresh instance, create-admin-user is the one that matters, because the README documents no self service signup for the first administrator. What is not written down anywhere in the repository is when to pick migrate over upgrade, and both names sit side by side in the scripts, so anyone running an existing database has to settle that on the docs site rather than from the source tree. clean-orphaned-records has the same problem: a maintenance command with no documented trigger condition. Two further entries serve code work rather than running it. server:swagger:generate builds the API reference served at plankanban.github.io/planka/swagger-ui, and gv regenerates server/version.js and client/src/version.js from the .ejs templates before a build.

Three Dockerfile stages, a squid proxy, and a healthcheck every ten seconds

There are two routes to a running image. The first is the published image on ghcr.io, driven by the compose file. The second is a local build, which the root package.json wraps in a single script.

bash
docker build -t planka .

The Dockerfile behind that command has three stages on Node 24. The server stage copies server/ into node:24-alpine, adds build-base and python3, then runs npm install, npm run build and npm prune --production. The client stage builds on node:24 with INDEX_FORMAT=ejs and DISABLE_ESLINT_PLUGIN=true, so the client bundle compiles without the lint plugin. The final stage returns to alpine, adds bash, python3 and squid, switches to USER node, and finishes like this:

dockerfile
HEALTHCHECK --interval=10s --timeout=2s --start-period=15s \
  CMD node ./healthcheck.js

VOLUME /app/data

EXPOSE 1337

CMD ["./start.sh"]

The volume at /app/data is the same one the compose file mounts, so attachment and upload data survives a container replacement. The README never mentions the squid package that the final image installs, so what that proxy fronts is not something you can confirm from the documentation. The healthcheck polls every 10 seconds with a 2 second timeout and a 15 second start period, which means a container that is still warming up is not marked unhealthy until the start period has passed.

Commented out config keys and files the README never explains

The compose file is the best configuration reference in the repository, and it is quiet about most of its own knobs. LOG_LEVEL, TRUST_PROXY, MAX_UPLOAD_FILE_SIZE, TOKEN_EXPIRES_IN, STORAGE_LIMIT, ACTIVE_USERS_LIMIT, PGSSLMODE and KNEX_REJECT_UNAUTHORIZED_SSL_CERTIFICATE all appear commented out, and no default is stated for most of them.

Two of those carry weight for anyone running the board behind nginx. TRUST_PROXY ships commented out, so a default install does not trust proxy headers and the connection details recorded for a request come from the proxy rather than the client. TOKEN_EXPIRES_IN is shown as 365 days, which sets the lifetime of a session token unless you override it, and a leaked browser session then stays useful for a year. PGSSLMODE exists because the docs note that knex does not pass query parameters from the connection string, so SSL settings have to travel as their own variables.

The repository also carries files with no accompanying README text: docker-backup.sh and docker-restore.sh at the root, a charts/ directory holding a Helm chart, and docker-compose-dev.yml beside Dockerfile.dev. Nothing tells you when to run the backup script, which database it dumps, or where the archive lands. If your upgrade plan depends on the restore path, you have to read both shell scripts before trusting them.

Editorial conclusion

PLANKA suits a team that wants its board on its own PostgreSQL and accepts a fair-code licence plus a Community edition that stops at desktop web use. It does not suit a team needing mobile access, recurring cards, guest roles, SSO or exports without paying for Pro, nor a team running a Community release older than 2.1.x. Before anything else, generate a new SECRET_KEY with openssl rand -hex 32, point DATABASE_URL at a Postgres instance you control, and confirm your Community version is 2.1.x or 2.2.x before reading anything about the Pro promote.

Frequently asked questions

What is Planka?

Planka is a self-hosted Kanban project tracking tool for teams, built in JavaScript. It gives you boards, lists and cards with drag-and-drop, real-time updates between users, markdown descriptions and notifications through more than 100 providers.

How do I install Planka with Docker?

The repository ships a compose file that pulls ghcr.io/plankanban/planka:latest, mounts a named volume at /app/data and publishes container port 1337 on host port 3000. Before starting, replace SECRET_KEY=notsecretkey with a value you generate yourself, and point DATABASE_URL at your own Postgres host.

How do I set up Planka after the container starts?

Set BASE_URL to the address your browser uses, run npm run server:db:create-admin-user against the same database, then open the instance and sign in as that administrator. The README documents no self-service signup, so this script is how the first account is created.

Is Planka free to self-host?

Yes for the Community edition, which the comparison table marks as free to self-host with your own database and your own backups. A separate PLANKA Pro edition adds mobile support, calendar, timeline, map and media views, templates, recurring cards, guest roles, SSO, exports and developer support, and the repository also links to hosted pricing at planka.app.

Is Planka open source?

The repository description calls it open source, while the licence section describes fair-code distributed under a Fair Use License and a PLANKA Pro/Enterprise License. It states four properties directly: source available, self-hostable, extensible, and enterprise licences available for additional features and support.

What can I do on a Planka board once I am logged in?

Cards carry markdown descriptions, attachments, comments and custom fields, plus a stopwatch and due dates. Changes sync between users without a refresh, and the REST API and webhooks are documented, with the API reference served from a Swagger UI.

Official sources

  1. Issues
  2. plankanban/planka on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/plankanban-planka.svg)](https://hysenlabs.com/projects/plankanban-planka)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/plankanban-planka.svg)](https://hysenlabs.com/projects/plankanban-planka)

Was this useful?