Flarum 2.0.0-rc.1 Released π
We've made it. Nearly three years of development, eight betas, 397 merged PRs, and 30 contributors later β Flarum 2.0 is now at Release Candidate 1.
β
Safe to use in production for early adopters. The path from here to stable is fully supported β upgrades from rc.1 through to 2.0.0 final will be smooth. Normal precautions apply: back up your database, test locally or on a staging environment first if you have one, and have a rollback plan.
π You're already running it. This very forum β discuss.flarum.org β has been updated to rc.1.
π§ͺ Want to try Flarum 2.0 first? Check out our nightly demo at nightly.flarum.site, rebuilt every day from the latest 2.x code.
π§ What "Release Candidate" actually means
An RC is a release we think is ready to ship. It's feature-complete, the API is frozen, and if nothing critical turns up, rc.1 becomes 2.0.0 with no functional changes.
Here's the deal:
- No more breaking changes. The extension API is locked. A 2.x-compatible extension built against rc.1 will still work on 2.0.0 final.
- A clean upgrade path from here on. If you're on rc.1, getting to 2.0.0 will be a plain
composer update β no surprises.
- We'll move fast on regressions. Anything reported against rc.1 that blocks real-world use gets bumped to the top of the pile.
And here's where you come in β we need people running this on real forums. The more setups we see, the fewer surprises at 2.0.0.
- Install it. Locally, or on a staging environment if you have one β ideally against a copy of your real data.
- Use it like you use your forum. Post, reply, moderate, upload, search, customise. Try the extensions you rely on.
- Tell us how it went β good or bad. Bugs, upgrade friction, extensions that break, UI papercuts, weird slowdowns. Also: "it just worked" is genuinely useful to hear.
Where to report:
- Bugs in core β flarum/frameworkissues
- General feedback, questions, extension behaviour βSupport
- Security issues β
security@flarum.org (please don't post publicly)
Not sure which bucket something belongs in? Post on discuss and we'll sort it.
β¨ What's new in rc.1?
rc.1 is a polish-and-hardening release. Aside from a handful of small additions requested during the beta cycle, the focus is on performance, security, and fit-and-finish. The changes below were added since beta.8 was released.
π Security hardening
A cluster of password-flow and session-management fixes land in rc.1.
- Password reset tokens are now expiry-checked on submission. Previously the expiry window was only validated when the reset form was rendered β an expired token could still complete a reset if submitted directly.
- Changing your password now invalidates all existing sessions. Every session, remember-me, and developer token for the user is dropped when the password changes.
- Requesting a new password reset deletes the stale one. Only a single valid reset token can exist for a user at any moment.
- Avatar-from-URL fetches are hardened. The Guzzle client used to retrieve remote avatars now disables redirects, enforces a short timeout, and rejects oversized responses before buffering them into memory.
- Logo, favicon and dark-logo uploads are now validated. Previously only avatars ran through the image validator β rc.1 introduces a shared
AbstractImageValidator and wires it into every image-upload controller, closing a gap where admin image endpoints accepted non-image uploads.
β‘ Performance
- Discussion-list N+1 queries eliminated. A cluster of N+1 patterns on the discussion list (tag permission subqueries, likes/groups eager loading, visibility guards on erasure requests and message counts) have been squashed β the forum index now issues roughly a quarter as many queries as in beta.8.
- New composite index on
notifications. Unread-count queries were becoming noticeably slow on large forums. A (user_id, is_deleted, read_at, type) composite index fixes it.
- Tag slugs resolve in one query.
TagFilter previously issued one query per slug; rc.1 batches them into a single whereIn.
- Frontend performance pass. Preconnect / DNS-prefetch hints on the document head,
fetchpriority applied to logo and preload hints, and a sessionStorage-based CSS loader that eliminates the flash of unstyled content that could occur on cold navigations. The viewport meta has also been relaxed so pinch-to-zoom is no longer blocked on mobile.
β Small additions
- Reset-settings button on extension admin pages. Each bundled extension's admin page now has a "Reset to defaults" button, backed by a new
DELETE /api/settings endpoint and a Settings\Event\Reset event that extensions can listen to for their own cleanup.
- HiDPI avatars. Uploaded avatars now generate
@2x and @3x variants automatically and the <Avatar> component renders a srcset, so avatars look crisp on retina and mobile displays.
- Abandoned-extensions sync runs weekly. The admin-facing abandoned-package warning system now re-syncs the flarum/abandoned-extensions list weekly, with a "Check Now" trigger available on demand and admin notifications when an installed extension becomes abandoned.
forum-widget extension category. A new category for widget-style extensions, sitting between themes and language packs in the extension list.
- Presence-channel authorization extender. The realtime extension gains a
Realtime::authorizePresenceChannel extender, letting extensions gate access to presence channels at the WebSocket auth layer.
π οΈ Fixes & polish
π± Frontend & mobile
ReplyPlaceholder shows avatar and badges on mobile when composing.
- Back-navigation no longer loses loaded pages or scroll position β
PaginatedListState now compares params by value instead of reference.
UserCard controls icon restored so the mobile controls button is visible again.
- Admin nav dropdown no longer flickers on mobile.
- Admin StatusWidget layout fixed on mobile β items now flow in a grid and the tools button spans the row.
- FontAwesome Kit no longer overrides
display: none on hidden icons. Tag-select and subscription dropdown markup cleaned up in the process.
- Bottom page padding is no longer cut off in certain layouts.
- Radio groups no longer collide β multiple radio groups on the same page no longer share a
name and interfere with each other.
- Admin avatar-driver select now shows the correct default on fresh installs, and the abandoned-sync status message has proper padding.
π§ Routing & URLs
- Trailing slashes on URLs no longer 404.
ResolveRoute now strips a trailing slash before dispatching, so /d/123-foo/ resolves the same as /d/123-foo.
- Extensions with malformed names no longer emit PHP warnings.
ExtensionManager now skips package names that lack the vendor/package format instead of crashing nameToId() with an undefined-array-key warning.
π·οΈ Tags
bypassTagCounts now works for non-admins holding the permission β the check was using the admin-only shortcut where it should have been calling hasPermission.
- Tags homepage meta description now uses your forum description (falling back to the
All Tags translation only when no description is set).
π Sticky
- Ambiguous
id column in the is_unread_sticky subquery fixed β extensions that join on discussions (e.g. byobu) no longer break MySQL with an ambiguous-column error.
π API & serialization
Attribute fields now correctly run through serializeValue β a long-standing bug where booleans like allowSignUp were emitted as strings has been fixed.
- Array values are preserved when an
Attribute with a Str cast returns an array, avoiding "Array to string conversion" errors in extensions.
Arr::serialize() now respects JsonSerializable objects like MessageBag.
π¬ Community wording
- Replaced "community" with "forum" in a user-facing string for consistency.
π± The ecosystem is ready
rc.1 is the signal to the extension ecosystem: the API is stable. If you maintain an extension, now is the time to publish your 2.x-compatible release.
Language packs β @rob006 has been coordinating language pack updates. If you maintain a translation, please check in on those threads.
Friends of Flarum β the FoF catalogue has near-complete 2.x coverage. Thank you to everyone involved.
Extension developers β final compatibility blockers are being prioritised between rc.1 and stable. If something in core is standing between you and a release, open an issue.
π Try it yourself
- Live demo β nightly.flarum.site, rebuilt daily
- Right here β discuss.flarum.org is running rc.1
- Update your install β
composer update -W, then php flarum migrate, php flarum cache:clear, and php flarum assets:publish (back up first, and test locally or on staging if you can)
π Thank you
Thanks to everyone who landed changes in this release, reported bugs, and tested the betas.
A special shout-out to @ClaudiusH β who has spent an enormous amount of time running the nightly builds, surfacing bugs big and small throughout the beta cycle, and tirelessly maintaining the German language pack. A huge chunk of the polish in this release traces back to his reports. Thank you, Claudius.
- @rafaucau β webpack-config Babel plugin cleanup #4498,
FormGroup radio name fix #4571
- @luceos β admin nav dropdown mobile flicker fix #4578, shared image validator #4579, communityβforum wording #4580
- @IanM β everything else
π Changelog
Added
- (core) reset-settings button and confirmation modal on extension admin pages, backed by
DELETE /api/settings and Settings\Event\Reset by @IanM #4522
- (core)
forum-widget extension category by @IanM #4543
- (core) HiDPI avatar srcset β generate @2x/@3x variants on upload and expose
avatarSrcset on the user resource by @IanM #4555
- (core) weekly sync of the abandoned-extensions list with admin notifications and manual "Check Now" trigger by @IanM #4560
- (realtime)
Realtime::authorizePresenceChannel extender for gating presence-channel access by @IanM #4573
Security
- (core) enforce expiry check on password reset token submission by @IanM #4550
- (core) invalidate active sessions when password is changed by @IanM #4551
- (core) delete stale password tokens when requesting a new reset by @IanM #4552
- (core) harden avatar-from-URL Guzzle client β disable redirects, add timeout and size limit by @IanM #4553
- (core) validate logo, favicon and dark-mode logo uploads via a shared
AbstractImageValidator by @luceos #4579
Fixed
- (core) suppress PHP warning when extension name lacks
vendor/package format by @IanM #4510
- (core) strip trailing slash from URI before route dispatch by @IanM #4511
- (core) incorrect bottom page padding by @IanM #4518
- (core)
Api\Serializer attribute fields now run through serializeValue so booleans no longer serialize as strings by @IanM #4530
- (core)
PaginatedListState::paramsChanged() uses value comparison so back-navigation preserves loaded pages and scroll by @IanM #4532
- (core) show avatar and badges in
ReplyPlaceholder composing state on mobile by @IanM #4533
- (core) preserve array values in
Attribute::serializeValue to avoid "Array to string conversion" for extensions returning arrays from Str-typed attributes by @IanM #4534
- (core) small correctness and accessibility fixes β serializer meta caching, queue exception handler,
@hasSection directive, Checkbox inputAttrs, FormGroup Switch aria-describedby by @IanM #4562
- (core) restore controls icon on
UserCard so the mobile controls button is visible by @IanM #4568
- (core) remove hardcoded radio input
name in FormGroup so multiple radio groups can coexist by @rafaucau #4571
- (core) prevent FontAwesome Kit from overriding
display on hidden icon elements by @IanM #4575
- (admin) improve
StatusWidget mobile layout on the dashboard by @IanM #4531
- (admin) avatar driver default value and abandoned-sync message padding by @IanM #4567
- (admin) nav dropdown flickers on mobile by @luceos #4578
- (sticky) qualify ambiguous
id column in is_unread_sticky subquery so extensions that join discussions no longer break by @IanM #4520
- (tags) use
hasPermission for bypassTagCounts so the permission works for non-admins on restricted tags by @IanM #4539
- (tags) use forum description for meta description on tags homepage by @IanM #4558
Changed
- (core) replace "community" wording with "forum" for consistency by @luceos #4580
- (webpack-config) remove deprecated Babel plugins from config by @rafaucau #4498
Performance
- (core) eliminate N+1 queries on the discussion list by @IanM #4508
- (core) add composite index on
notifications to fix slow unread-count queries by @IanM #4509
- (core) frontend performance improvements β preconnect hints,
fetchpriority, FOUC fix, viewport by @IanM #4561
- (tags) resolve tag slugs in a single batch query in
TagFilter by @IanM #4563