What’s new Flarum 2.0.0-rc.3 Released - Built by the Community, Almost Ready for Everyone

Forums made
simple.

Beautiful, fast, and free — Flarum is the open‑source forum software your community has been waiting for.

Free
Forever
MIT
Licensed
Open
Source
discuss.flarum.org
Flarum forum screenshot

Everything you need

Community
platform

Flarum scales from small hobby communities to large enterprise forums. Customise every aspect through a rich ecosystem of extensions.

Discover extensions

Groups & permissions

Assign permissions to groups, control member access across categories, and keep things tidy with built-in moderation and flagging.

Styling & themes

Customise via admin settings, install themes, or write custom CSS that propagates across your entire forum automatically.

Powerful editor

Choose from lightweight Markdown editors to full WYSIWYG — Flarum supports both, meeting users wherever they are comfortable.

Notify & engage

In-browser notifications, email digests, and real-time websocket extensions keep your community active and coming back.

Extend endlessly

Hundreds of community-built extensions are available. Build your own, or commission custom development — the API makes it possible.

Secure by default

Built on Laravel with security best practices throughout. Regular core updates keep your community protected.

Get involved

Join the community

Flarum is built by passionate developers and contributors. There’s always room for more.

Build Extensions

Learn how to harness Flarum's extensibility to create extensions and customise your community.

Start Extending

Contribute

Help us make Flarum better. Every bug report, pull request, and documentation improvement counts.

Start Contributing

Get Support

Have a question? The Flarum community is active and welcoming — find answers on Discuss.

Visit Discuss

News & updates

Latest from the blog

Flarum 2.0.0-rc.3 Released - Built by the Community, Almost Ready for Everyone

Flarum 2.0.0-rc.3 Released 🎉 — and 2.0 is almost here

This is the one we've been working toward for years. Flarum 2.0 is no longer on the horizon — it's right in front of us. Today we're shipping 2.0.0-rc.3, and with each release candidate the picture gets clearer: real forums, running real communities, on 2.0 today, with more upgrading every single day.
rc.3 is a fast, focused follow-up to rc.2 — 10 merged PRs just a week later — but the bigger story is the momentum behind it. The release-candidate series is doing exactly what it's meant to do: people are running 2.0 in production, telling us what they find, and we're turning fixes around in days. The bug reports are getting rarer and the edges are getting smoother. That's what the road to a stable 2.0 looks like, and we're nearly at the end of it.
🚀 Production-ready for early adopters — and people are already there. The upgrade from rc.2 is a plain composer update. Back up your database, test on staging if you can, keep a rollback plan — the usual.
👀 This forum runs it. discuss.flarum.org is on rc.3. So is the nightly demo, rebuilt daily from the latest 2.x code. You're looking at 2.0 right now.
💬 Already upgraded? Tell us. Drop a note inSupport — every "running it in prod, all good" report builds confidence for the next forum about to take the leap.

🧭 Where we are — the last mile

We're in the final stretch. The release-candidate promise still holds, and every point of it is now battle-tested in production:
  • The API is frozen — for real, proven by real extensions. An extension built against rc.1 or rc.2 works unchanged on rc.3 and will work on 2.0.0 final. Extension authors: now is the time to ship your 2.0-compatible releases.
  • The upgrade path is clean. rc.2 → rc.3 → 2.0.0 is composer update the whole way. The forums upgrading daily are proof.
  • Regressions go to the top of the pile — and there are fewer of them every cycle.
rc.3 is a maintenance and hardening release: a couple of small new diagnostics, otherwise real-world rough edges sanded down. The fast turnaround is the whole point — when you report something, we'd rather ship the fix in a week than sit on it. Every report you send moves 2.0 final closer. Keep them coming.
Where to report:

🛠️ What changed in rc.3

🗄️ Database & queue robustness

The headline of this cycle is making Flarum fail loudly and early instead of mysteriously:
  • Database driver/server mismatches are now detected and surfaced. Since 2.x, Flarum treats MariaDB and MySQL as distinct drivers with their own connection classes and query grammars — they are not interchangeable. A misconfigured driver against the wrong server was behind a whole class of "some queries just fail" reports; Flarum now spots the mismatch and tells you, rather than letting it manifest as random query errors.
  • The full Queue Pause/Resume surface is stubbed on QueueFactory. Flarum hands its QueueFactory to Illuminate's worker in the role normally filled by the full QueueManager, but the Factory contract only guarantees connection(). The missing methods the worker and queue commands reach for are now stubbed, so queue tooling doesn't blow up on a method that was never there.
  • The queue worker no longer crashes on a null connection name. illuminate/queue 13.15 tightened the type on its WorkerIdle event to require a string connection name; Flarum never set one, so the worker threw a TypeError on every idle tick. Flarum now names its queue connection, which keeps the worker happy across Illuminate releases — the same "a dependency bump shouldn't be able to crash the worker" hardening as the stub above.

🚦 Error handling

  • Forum error handling now does content negotiation — errors are rendered in the format the client actually asked for, instead of assuming one.

📱 Frontend & mobile polish

  • The user count and list refresh after creating a user in admin, so the new account shows up without a manual reload.
  • The post divider is no longer lopsided on mobile.
  • Emoji reserve a square box (img.emoji), eliminating the layout shift (CLS) that nudged text around as emoji loaded.
  • Mentions in a post now align with the rest of the text instead of sitting slightly off the baseline.

🧩 Extension compatibility

  • Tags and Sticky no longer fail to initialize alongside Realtime. With both enabled you could hit flarum-tags failed to initialize / TypeError: mt(...) is not a constructor. The cause was load order: Realtime registers a JS extender that Tags and Sticky consume, but they weren't guaranteed to load after it. Declaring Realtime as an optional dependency fixes the ordering — caught from a community bug report, exactly the kind the RC series is for.

⚡ Performance

  • N+1 group_user queries are gone when serializing users — group membership is now loaded in bulk instead of per-user, a meaningful win on any list of accounts.

💙 This is a community release

Here's the part we're proudest of: most of rc.3 was written by the community, not the core team. Five of the ten PRs this cycle came from contributors outside the core — people who hit something, fixed it, and sent it back upstream. That's not a footnote; that's the whole point of Flarum, and it's exactly the energy that carries a project across the finish line to a major release.
If you've ever thought about contributing, this is the moment. 2.0 is being built in the open, in real time, by people like you. Every PR, every bug report, every "I upgraded and here's what happened" makes the final release better.
Contributors this cycle:
  • @datitisev — content negotiation for forum error handling #4677, mention alignment #4692
  • @davetodave178 — refresh user count and list after user creation #4687
  • @KBExit — lopsided post divider on mobile #4691
  • @IanM — database mismatch detection, queue surface stub, queue worker connection-name fix, emoji CLS, the N+1 fix, and the Realtime load-order fix

🚀 Be part of it

The best thing you can do for 2.0 right now is run it. Every forum that upgrades is one more real-world proving ground, and one more vote of confidence for the next person on the fence.
  • See it livenightly.flarum.site, rebuilt daily, and right here on discuss.flarum.org
  • Upgrade your installcomposer update -W, then php flarum migrate, php flarum cache:clear, and php flarum assets:publish (back up first, and test on staging if you can)
  • Then come back and tell us — what worked, what didn't, what you'd want in 2.0 final
We're close. Let's bring 2.0 home together. 💪

📋 Changelog

Added

  • (core) detect and surface a database driver/server mismatch (e.g. MariaDB vs MySQL) by @IanM #4682
  • (core) content negotiation for forum error handling by @datitisev #4677

Fixed

  • (core) refresh the user count and list after user creation by @davetodave178 #4687
  • (core) lopsided post divider on mobile by @KBExit #4691
  • (core) stub the full Queue Pause/Resume surface on QueueFactory by @IanM #4683
  • (core) queue worker TypeError on a null connection name with illuminate/queue 13.15+ by @IanM #4700
  • (mentions) align mentions in post with the rest of the text by @datitisev #4692
  • (emoji) reserve a square box for img.emoji to avoid layout shift (CLS) by @IanM #4685
  • (tags, sticky) declare flarum/realtime as an optional dependency so the realtime extender loads before its consumers, fixing TypeError: mt(...) is not a constructor by @IanM #4699

Performance

  • (core) fix N+1 group_user queries when serializing users by @IanM #4696

Flarum 2.0.0-rc.2 released

Flarum 2.0.0-rc.2 Released 🎉

Six weeks ago we shipped 2.0.0-rc.1 and asked you to do one thing: run it on real forums and tell us what breaks. You did — and 2.0.0-rc.2 is the result. 41 merged PRs, almost all of them fixes traced directly back to reports from people running rc.1 in production, on staging, and on the nightly demo.
Still production-safe for early adopters, and the upgrade from rc.1 is a plain composer update. Back up your database, test on staging if you can, keep a rollback plan — the usual.
👀 This forum is already on it. discuss.flarum.org has been updated to rc.2.
🧪 Want to try before upgrading? The nightly demo at nightly.flarum.site is rebuilt daily from the latest 2.x code.

🧭 Where we are

Nothing about the release-candidate promise from rc.1 has changed:
  • The API is still frozen. An extension built against rc.1 works unchanged on rc.2 and will work on 2.0.0 final.
  • The upgrade path stays clean. rc.1 → rc.2 → 2.0.0 is composer update the whole way.
  • Regressions go to the top of the pile. That's exactly what this release is made of.
rc.2 is a maintenance and hardening release — no new surface area to speak of, just a lot of real-world rough edges sanded down. If rc.1 was "we made it to RC", rc.2 is "you found the bugs, we fixed them." Please keep them coming.
Where to report:

🛠️ What changed in rc.2

🔔 Notifications & email

The biggest cluster this cycle. Several people reported duplicate notifications and emails under load — all now fixed:
  • Notification and email duplicates from a queue race in NotificationSyncer are eliminated.
  • The notification dedup query never matched non-null data on MySQL, which is what let duplicates through in the first place.
  • Transactional emails now send in the recipient's preferred locale rather than the sender's or the forum default.
  • The email logo now resolves via the flarum-assets disk, so it renders correctly regardless of storage configuration.
  • The SMTP ping threshold dropped to 20s to survive idle-disconnects from relays that hang up aggressively.

📡 Realtime on iOS Safari

@ekumanov did a deep dive on WebSocket behaviour when iOS Safari backgrounds a tab, and landed a series of fixes:
  • Reconnect and catch up on missed events after the tab returns from the background.
  • Reconstruct Pusher on reconnect to get around iOS's lives:2 connection budget.
  • Only force-reconnect on visibilitychange on iOS, leaving other platforms alone.
  • Plus correct boolean-setting casting and ordering realtime:info users by joined_at.

🗂️ Queue & jobs

  • Per-class queue routing on AbstractJob is restored — jobs can again declare their own queue.
  • QueueFactory::getPausedQueues() keeps Flarum compatible with illuminate/queue v13.11+.
  • Orphaned queued jobs no longer spam duplicate ModelNotFoundException logs, and EloquentBuffer now guards against orphaned/mock models.

🔍 Search

  • PostgreSQL search configuration handling is hardened.
  • Extend\SearchDriver class-string types widened to SearcherInterface so custom drivers type-check cleanly.
  • The search clear button no longer opens the modal when clicked, and is hidden when collapsed in tablet mode.

📱 Frontend & mobile polish

  • Mobile discussion total post count now updates when you reply — the scrubber header was rendering a reused vnode that went stale (#4602).
  • User badges sit correctly next to the username instead of drifting left of the avatar.
  • Native tooltip flash, async teardown leaks, and dynamic tooltip text are all resolved.
  • Flash of unstyled content is gone — the async-CSS dual path was replaced with a render-blocking stylesheet.
  • text-overflow: ellipsis restored on long button labels, and the admin extension danger badge stays visible on long names.
  • TextEditor.onbuild no longer races against an async Mithril redraw.
  • Browsers without XSLT support boot again thanks to a bundled polyfill.

🔒 Privacy & correctness

  • GDPR export downloads are hardened with an audit trail, single-use links, and an active expiry check.
  • The UserResource groups relationship is scoped to viewable groups, so hidden group membership doesn't leak.
  • UserSecurityPage no longer crashes when the user model loads asynchronously.
  • Discussion PATCH responses surface event posts, and title changes route through rename().
  • The profile author filter uses the user slug, not the username.

🏷️ Extensions

  • (tags) the subquery for permitted tag IDs is restored (a regression from #4502), and legacy unused background columns are dropped from the tags table.
  • (flags) the literal 'undefined' is gone from the Inappropriate reason, and FlagPostModal is lazy-loaded.
  • (nicknames) min/max length settings are cast to int before reaching Schema\Str.

⚡ Performance

  • JsDirectoryCompiler skips MIME detection when the file extension already tells it what it needs to know.

💙 Thank you

rc.2 exists because people ran rc.1 and reported what they found. Special thanks to @ClaudiusH, who continues to run the nightly builds and surface bugs big and small — including the mobile post-count regression fixed here.
Contributors this cycle:

🚀 Try it / upgrade

  • Live demonightly.flarum.site, rebuilt daily
  • Right here — discuss.flarum.org is running rc.2
  • Update your installcomposer update -W, then php flarum migrate, php flarum cache:clear, and php flarum assets:publish (back up first, and test on staging if you can)

📋 Changelog

Added

  • (core) per-class queue routing on AbstractJob by @IanM #4656
  • (core) QueueFactory::getPausedQueues() for illuminate/queue v13.11+ compatibility by @forumaker #4673

Fixed

  • (core) add XSLT polyfill so the forum still boots on browsers without XSLT support by @IanM #4359
  • (core) misaligned user badges in posts — positioned relative to the username instead of the avatar by @luceos #4582
  • (core) hide the search clear button when collapsed in tablet mode by @huoxin233 #4594
  • (core) prevent the search modal from opening when the clear button is clicked by @huoxin233 #4595
  • (core) prevent discussion list cache wipe on back-navigation to tag pages by @IanM #4598
  • (core) send transactional emails in the recipient's preferred locale by @IanM #4627
  • (core) restore text-overflow: ellipsis on long button labels by @IanM #4628
  • (core) scope the UserResource groups relationship to viewable groups by @IanM #4629
  • (core) add missing getHidden() to the Log\Context\Repository stub by @IanM #4633
  • (core) avoid duplicate ModelNotFoundException logs on orphaned queued jobs by @IanM #4634
  • (core) resolve VersionerInterface from the container and cache rev-manifest reads by @IanM #4638
  • (core) track avatar HiDPI variants on users to remove srcsetFor() filesystem calls by @IanM #4639
  • (core) resolve the email logo URL via the flarum-assets disk by @IanM #4640
  • (core) lower the SMTP ping threshold to 20s to survive idle-disconnect from relays by @IanM #4641
  • (core) notification dedup query never matching non-null data on MySQL by @IanM #4645
  • (core) notification and email duplicates from a queue race in NotificationSyncer by @IanM #4647
  • (core) TypeError in the Revised event when post content is NULL by @IanM #4648
  • (core) prevent UserSecurityPage crash when the user loads asynchronously by @datlechin #4651
  • (core) send the user slug, not username, for the profile author filter by @IanM #4655
  • (core) TextEditor.onbuild race against async Mithril redraw by @IanM #4657
  • (core) surface event posts in discussion PATCH responses and route title changes via rename() by @IanM #4658
  • (core) harden pgsql search configuration handling by @IanM #4663
  • (core) replace the async-CSS dual path with a render-blocking stylesheet to fix FOUC by @IanM #4664
  • (core) widen Extend\SearchDriver class-string types to SearcherInterface by @IanM #4668
  • (core) guard EloquentBuffer against orphaned/mock models by @IanM #4669
  • (core) resolve native tooltip flash, async teardown leaks, and dynamic tooltip text by @huoxin233 #4674
  • (core) mobile discussion total post count not updating on reply by @IanM #4678
  • (admin) keep the extension danger badge visible on long names by @IanM #4660
  • (realtime) reconnect the WebSocket and catch up on missed events after iOS Safari backgrounding by @ekumanov #4590
  • (realtime) cast boolean setting correctly by @IanM #4624
  • (realtime) order users by joined_at in realtime:info by @IanM #4630
  • (realtime) reconstruct Pusher on iOS reconnect to bypass the lives:2 budget by @ekumanov #4654
  • (realtime) only force-reconnect on iOS visibilitychange by @IanM #4662
  • (gdpr) harden export download with an audit trail, single-use links, and an active expiry check by @IanM #4642
  • (tags) restore subquery for permitted tag IDs (regression from #4502) by @IanM #4649
  • (flags) drop literal 'undefined' from the Inappropriate reason and lazy-load FlagPostModal by @IanM #4659
  • (nicknames) cast min/max length settings to int before passing to Schema\Str by @IanM #4599

Changed

  • (tags) drop legacy unused background columns from the tags table by @Abdooo2235 #4529

Performance

  • (core) skip MIME detection in JsDirectoryCompiler when the file extension already matches by @IanM #4632

Community Update: New Sponsor & 'New' Teammember

I am very pleased to share with you that we have a new sponsor through GitHub. Hostinger (https://github.com/hostinger | https://www.hostinger.com/) is supporting Flarum with 100$ / month. Thank you very much - this is a huge contribution for our Budget helping us to make Flarum even greater!
If you are also considering to support Flarum, here is how: https://discuss.flarum.org/contribute .
Additionally I am very happy to announce that our former Community Manager @jordanjay29 will be joining the @Flarum Team once again. He will be our "Flarum Morale Officer" - helping us be a better team - helping us shaping a better Flarum. Open Source work is hard, every help counts. Getting help from someone knowing Flarum and the Community very well will have a very positive impact.
As you know we are working hard on delivering Flarum v2 to you. RC2 is just around the corner which brings us to the final release one step closer. We are also working on bringing an updated website to you - bringing back a listing of all openly available Flarum extensions. So there is much to look out for. Thanks for sticking with us - every Flarum member and every Flarum community counts!

Our partners

Built with the best tools

We’re grateful to these companies who generously donate their products to the Flarum project.

Funded by

Flarum 2.0 was made possible with financial support from the NLnet Foundation through the NGI Zero grant programme.