# FlaskBB: four services in a container, one process from source

> FlaskBB is a self-hosted forum on Flask, distributed as a Docker stack of PostgreSQL, Valkey, a Celery worker and gunicorn, and also as a source checkout driven by make. The two paths do not share a port, and the newest published release is still a 3.0.0 candidate while the package metadata calls the project stable.

**flaskbb/flaskbb** — A classic Forum Software in Python using Flask.

- Repository: https://github.com/flaskbb/flaskbb
- Stars: 2,666 · Forks: 692
- Language: Python
- License: NOASSERTION
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/flaskbb-flaskbb

## The release stack is four services and the checkout is one process

Two documented routes lead to a running forum, and they differ in port, in process count and in what you have to configure by hand. The container route pulls a published image, built for linux/amd64 and linux/arm64:

```bash
docker pull ghcr.io/flaskbb/flaskbb:latest
```

The only tag written down is `latest`, so nothing in the instructions pins a version of the image. Building the stack from the checkout instead means copying the example environment file, which is where the three secrets live:

```bash
git clone https://github.com/flaskbb/flaskbb.git
cd flaskbb
cp docker/.env.example docker/.env
```

`SECRET_KEY`, `POSTGRES_PASSWORD` and the `ADMIN_*` variables are set in `docker/.env`, and the stack is described as complete for releases: PostgreSQL, Valkey, a Celery worker and gunicorn.

```bash
docker compose -f docker/docker-compose.yaml up -d
```

That route serves the forum on localhost:8000, and two further documents sit behind that compose file, `docker/README.md` for configuration and reverse proxy setup and `docker/DEVELOPMENT.md` for running from a checkout. The source route is four make targets and a different port, `make devconfig`, `make install`, `make run`, then localhost:5000, with `make install` asking for the administrator's username, email and password. The port a reverse proxy has to target therefore depends on which route you took, and the two are 3000 apart.

## The version number is not written in the project table

pyproject.toml starts with `name = "FlaskBB"` and `dynamic = ["version"]`, so the version is not in the file, and the root carries `hatch_build.py`, a build hook that produces it when the package is built. Reading the version therefore means reading releases. The list shows `v3.0.0rc3` published 2026-09-28, `v2.2.1` on 2026-07-04 and `v2.2.0` on 2026-02-18, so the newest artifact is the third candidate of 3.0.0 and its tag attaches the suffix without a separator, while both stable tags are plain version numbers. The same file declares `Development Status :: 5 - Production/Stable`, `Framework :: Flask`, `Operating System :: OS Independent` and classifiers for Python 3.12 and 3.13, with `requires-python = ">=3.12"`. The metadata describes a stable, platform-independent package while the release channel is still on a candidate. One more property of the dependency list is worth knowing before an upgrade: all 41 entries are floors, from `alembic>=1.20.0` at the top to `requests>=2.34.2` at the bottom, and not one carries an upper bound, so nothing in the project table stops an upstream major release from arriving underneath you.

## The forum package depends on two of its own plugins

Two entries in that 41-line dependency list are FlaskBB plugins: `flaskbb-plugin-conversations>=3.0.4` and `flaskbb-plugin-portal>=3.0.2`. They sit in `[project].dependencies` beside Flask and SQLAlchemy, so an ordinary install of the forum pulls two plugins from the same author, at floors of 3.0.x while the newest release of the forum itself is a 3.0.0 candidate. That sits against the rule stated for the plugin system, which is that plugins are regular Python packages discovered through entry points and that a newly installed plugin stays disabled until someone enables it in the admin panel or on the command line. Those two cannot be left off. The rest of the list is where the stack shows through: Flask-Alembic and alembic for migrations, Flask-Allows2 behind the group based permissions and per-forum moderators, Flask-Limiter for rate limiting, Flask-Caching, Flask-Mail, PyJWT, mistune with Pygments for the Markdown posts and their syntax highlighting, Pillow for attachments and avatars, pluggy for the plugin system, Flask-Themes2 for the theme. `Flask-DebugToolbar` and `flask-debugtoolbar-warnings` are in that same list rather than in an optional group, so the toolbar ships with a normal install.

## Twelve names are declared phony and five working targets are not

The Makefile opens with a .PHONY line and a default goal:

```make
.PHONY: clean install help test lint isort run dependencies docs wheel upload dev-plugins
.DEFAULT_GOAL := help

frontend: ## Runs the Vite watcher for Aurora
	cd flaskbb/themes/aurora && npm run watch

frontend-build: ## Builds both themes
	cd flaskbb/themes/aurora && npm run build && cd ../aurora_dark && npm run build
```

Twelve targets are declared phony, and the visible recipes define five more that are not: `frontend`, `frontend-dark`, `frontend-build`, `devconfig` and `format`. Since `make` looks for a file named after each target before running its recipe, an undeclared target that happens to match a file name in the working tree will be reported as up to date instead of run. `devconfig` and `install` also declare `dependencies` as a prerequisite, and that recipe is `@uv sync 1>/dev/null`, so the environment sync happens first with its output thrown away and a failure prints nothing. Two names in the phony line, `lint` and `isort`, sit below the point where this copy of the file ends, while the target that sorts imports is `format`, running `uv run ruff check --fix --select I`.

## `make run` starts the debugger with the PIN prompt disabled

The development server target is a single line, and it is the one the quick start tells you to run:

```make
run: ## Runs the development server with the development config
	WERKZEUG_DEBUG_PIN=off uv run flaskbb run --debugger --reload --debug
```

Three flags do ordinary development work: `--reload` restarts on file changes and `--debug` puts Flask in debug mode. The third, `--debugger`, is the one that matters for reading the line. It asks the Werkzeug server to install its interactive debugger in the browser, and the PIN that normally stands in front of that debugger is switched off by the environment variable in front of the command. So the configuration you get from `make run` is deliberately the one with nothing between a browser and the debugger, and the quick start sends you to localhost:5000 straight after. That is a machine you control, and it stays that way as long as the port is not published. It is not a line to carry into a deployment: the production path in the same README is gunicorn behind a reverse proxy with Redis and Celery, and the container path runs gunicorn inside compose.

## Search is offered for two databases and the stack ships Valkey

The feature list gives full-text search for PostgreSQL and SQLite, extendable through plugins. The release stack introduced earlier runs PostgreSQL, Valkey, a Celery worker and gunicorn, and the Python dependency that covers the cache and the broker is `redis>=8.1.0`, while the production guide is written around Redis. So the container path and the source path do not use the same name for the same job, and SQLite, the second database search is offered for, appears in neither the stack description nor the dependency list. In fact no database driver is named in the project table at all, neither for PostgreSQL nor for SQLite, so how the connection is made is settled somewhere the metadata does not record. Two entry scripts sit in the root for the pieces the stack needs, `celery_worker.py` for the worker and `wsgi.py` for the application object, and a `logs/` directory is committed next to them. Development around the themes runs through Node rather than Python: the two Aurora variants have their own watch and build targets using `npm run watch` and `npm run build`, and `biome.json` in the root is the linter that goes with that side of the tree.

## A plugin takes three commands and the last one is the switch

The plugin flow is written as three commands, and each does a different job:

```bash
uv pip install flaskbb-plugin-like
uv run flaskbb plugins install like
uv run flaskbb plugins enable like
```

The first puts the package on the interpreter, the second registers it with the forum, and the third is the switch. The rule stated beside them is that plugins are discovered through entry points and that a newly installed plugin stays disabled until it is enabled in the admin panel or with the CLI, which is why the last command cannot be dropped even though the first two succeed. Browsable plugins and themes live in the extension registry at flaskbb.com/registry/, and both scaffolding templates, `cookiecutter-flaskbb-plugin` and `cookiecutter-flaskbb-theme`, live in the personal `sh4nks` account rather than under the `flaskbb` organisation. The development side expects more plugins again: `make dev-plugins` installs seven sibling checkouts as editable packages from `../`, being portal, conversations, like, vote, ranks, test-mail and stopforumspam. So there are three different plugin sets in play, two in the dependency floors, one in the registry, and seven in the Makefile.

## Two translation services are named and a logs directory is committed

Translations are pointed at Weblate in the contributing section, with a localization guide for adding a language, and the repository root carries a `.tx/` directory at the same time, so two translation services are referenced for the same job and neither file says which one is current. `babel.cfg` sits in the root for message extraction, and `.readthedocs.yaml` covers the documentation build, which is Sphinx because `make docs` runs sphinx-build. Language coverage is stated as more than a dozen languages without a count, and the internationalisation stack in the dependency list is Flask-BabelPlus with Babel, pytz and Unidecode, so one feature rests on four packages. The root also mixes tooling configurations for three languages: `pyrightconfig.json` for type checking the Python side, `biome.json` for the theme sources, and `.pre-commit-config.yaml` for the hooks. Contributing is three commands, `uv sync`, `make test` and `make format`, with `uv.lock` pinning the resolved environment.

## Conclusion

FlaskBB suits a self-hosted forum when you want the whole stack in one compose file, since it brings up PostgreSQL, a cache, a Celery worker and gunicorn together and serves on port 8000, and it suits an existing deployment less well when you need a pinned stable release, because the newest published artifact is v3.0.0rc3 while the metadata still declares Production/Stable. Three things are worth checking before you install it. The version string is not in the project table, so read the release list instead of the metadata. Two of the project's own plugins are hard dependencies, so a plain install is not a plugin-free install. And the license deserves a direct look: pyproject.toml declares BSD-3-Clause with license-files = ["LICEN[CS]E"], the README points at LICENSE, NOTICE and AUTHORS, and the repository's own license metadata field carries no value at all.

## FAQ

### What does FlaskBB actually give you in a forum?

Forums, topics and posts with categories, unread tracking and a topic tracker; Markdown posts with syntax highlighting, emoji and an editor toolbar; attachments and avatars; group based permissions with per-forum moderators; an admin panel for users, groups, forums, reports, plugins and settings; a plugin system built on pluggy; the Aurora theme in a light and a dark variant; a command line interface; and translations for more than a dozen languages.

### Is the current FlaskBB release a stable one?

The newest published release is v3.0.0rc3, dated 2026-09-28, after v2.2.1 on 2026-07-04 and v2.2.0 on 2026-02-18. pyproject.toml still declares the Development Status :: 5 - Production/Stable classifier and requires-python ">=3.12", so the metadata and the release channel say different things.

### Do I need Docker to run FlaskBB?

No. Running from source needs Python 3.12 or newer and uv, then make devconfig, make install and make run, after which the forum is served on localhost:5000. The container route pulls ghcr.io/flaskbb/flaskbb:latest for linux/amd64 and linux/arm64 and serves on localhost:8000.

### Which databases does FlaskBB support for full-text search?

The feature list names PostgreSQL and SQLite, extendable through plugins. The release stack it ships runs PostgreSQL with Valkey, and the dependency list pins redis>=8.1.0 for the cache and broker while naming no database driver at all.

## Sources

- [flaskbb/flaskbb on GitHub](https://github.com/flaskbb/flaskbb)
- [Issues](https://github.com/flaskbb/flaskbb/issues)
- [README](https://github.com/flaskbb/flaskbb/blob/master/README.md)
- [Releases](https://github.com/flaskbb/flaskbb/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/flaskbb-flaskbb
