Group stages, knockouts and Swiss rounds on your own server
Bracket is a self-hosted web app for running tournaments. A tournament is split into consecutive stages, for instance round-robin pools followed by a single-elimination bracket, and a public dashboard tracks scores and standings as the event goes on. The backend is async Python on FastAPI, the frontend is React built with Vite and Mantine, and the database is PostgreSQL.
Swiss pairings built from each round's results
- Formats that mix: single elimination, round-robin and Swiss. Each stage holds one or more groups or brackets, and the teams that qualify move on to the next stage, so a Swiss phase can feed a final knockout bracket.
- Dynamic Swiss: matchups for a Swiss round are generated from the results of earlier rounds. A team flagged inactive is left out of the next round.
- One-click schedule, manual fixes: a single button gives every unscheduled match a court and a start time, and any match can then be dragged to another court or slot. Match length and the break between matches can also be set per match.
- Configurable rankings: points for a win, a draw or a loss, plus an option to add match scores to the standings. One tournament can hold several rankings.
- Public dashboard: each tournament gets its own page at a chosen slug, with a logo, meant to be shown to the public. It stays private until the visibility option is switched on.
Team-only model, Postgres backend, 3.0 still a release candidate
The project says it fills a gap. Its docs state that GitHub has no complete open-source tournament system and that closed alternatives are usually paid and expensive. They add that the Swiss-system tools the author knows of handle only Swiss, which rules out opening with Swiss rounds and closing on a knockout bracket.
Everything runs through teams. Players are optional and only displayed. For individual events, the docs suggest one team per participant, named after them, with no players inside. "Court" is just as loose: a badminton court in the docs' example, or any resource a match needs, such as a map in an online game.
PostgreSQL is mandatory, and the API and the UI are separate pieces. The backend reads its database address from PG_DSN. The frontend is a static Vite build that calls the API; when it is served from another address, VITE_API_BASE_URL has to be set on its side and CORS_ORIGINS on the backend's. In 3.0, SERVE_FRONTEND lets FastAPI serve both from one domain, with the API moved under /api. For production the docs require a JWT_SECRET and non-default admin credentials, and ALLOW_USER_REGISTRATION turns off open sign-up.
The latest stable release, v2.2.5, is from August 8, 2025. Version 3.0.0-rc1 came out as a pre-release on December 29, 2025. It moves the frontend from Next.js to Vite and renames the NEXT_PUBLIC_* variables to VITE_*. No final 3.0 had followed by October 27, 2026, although the README and docs on the master branch already describe it. The configuration page still calls the project a beta. Of the 356 commits pushed to master in 2026, 341 are Dependabot dependency bumps.
One security fix exists only on master. The dashboard access-control fix, merged on April 14, 2026, stops anonymous visitors from reading the teams, courts, rankings and stages of a tournament whose dashboard is not public. The v2.2.5 and v3.0.0-rc1 code lacks that check, and ghcr.io/evroon/bracket:latest is the v3.0.0-rc1 image, so getting the fix means building Bracket from master.
