Administrator comparing two versions of a community control panel on a widescreen monitor

XenForo 2.3 is not a skin. It removes jQuery, ships a second colour variation in the same style, converts uploads to WebP, and lets members sign in with a passkey. It will also white-screen a board whose add-ons still call $('selector') or whose parent style is a 2.2 fork of PAGE_CONTAINER. The changelog is the easy part. The upgrade is a staging job.

This is not a node-tree redesign, not a portal, and not an engagement checklist. Those articles already assume you are on 2.3. This one is the decision and the path: what 2.3 actually added, what it broke on purpose, who should wait, and the order of operations that keeps a live board from becoming a restore.

You can jump from any earlier XenForo 2 release. You do not install 2.2.x as a stepping stone. You also cannot downgrade. The only undo is the backup you took before Tools → Upgrade check.

Should you upgrade this month?

Three honest answers. Pick one.

Situation Upgrade? Why
New board, or a 2.2 board with stock style and a short add-on list, all vendors already shipping 2.3 builds Yes — this month You get style variations, WebP, passkeys, webhooks, and a smaller front-end without a six-week merge
Live board with a premium style, ten third-party add-ons, and a vendor who has not published a 2.3 package Stage it. Do not one-click production. The core upgrade is fine. The crash is the first add-on that still binds jQuery or SwiftMailer
You still run XenForo 1 styles or add-ons, or you cannot restore from backup tonight No XF1 packages must come off before 2.3. No backup means no upgrade

“Worth it” is not a feature list. It is whether you can put the same members back on a working board on Monday. 2.3 is worth that work for almost every board that is still on 2.2 and whose add-ons have 2.3 builds. It is not worth a Friday-night ACP click on a heavily customized production box.

If you already run 2.3, stop here and go do the node and engagement work. This article will not make 2.3.10 more 2.3.

What 2.3 actually changed

Ignore marketing adjectives. These are the switches an admin will touch, or the breaks a developer will hit.

JavaScript without jQuery

2.3 removes jQuery as a core dependency. Official 2.3 materials describe a large rewrite onto standard ES6: namespaced events on native handlers, animations on XF.Animate / XF.Transition instead of jQuery queues, and the old monolithic bundle split into modules that load when the DOM actually needs them (defer in <head>).

What that means on your board:

  • Template modifications and add-ons that still call $('selector'), $.ajax(), or .on() will fail. The replacements are document.querySelectorAll(), fetch(), addEventListener(), or the XenForo wrappers XF.ajax(), XF.ajaxAbortable(), and XF.on().
  • Legacy Select2 dropdowns fail. 2.3 uses Tagify.
  • Legacy star-rating scripts fail. 2.3 uses XF.BarRating.

This is the number-one silent upgrade failure. The ACP finishes. The forum list renders. The first click that needed custom JS does nothing. That is not “2.3 is slow.” That is an add-on still written for 2.2.

Style variations and native dark mode

One style can now ship two variations: default and alternate. They hook the browser prefers-color-scheme media query, and guests get a footer gadget that flips the variation without a reload.

This is not “install a second dark style and hope the IDs match.” It is one style, two palettes. Child-style work you already know still applies: put experiments in a child, not in the parent you will overwrite. The nodes article already said how 2.3 icons and variations interact. Do not redo that extra.less here. Do test both variations after the upgrade. A property marked variation-aware can differ between light and dark. An image you paste into extra.less will not flip unless you write that flip.

Colour properties moved from static hex toward HSL components exposed as CSS variables. Official Less helpers xf-intensify and xf-diminish are variation-aware: they darken a light variation and lighten a dark one so contrast does not collapse. If your child style hard-codes #1a1a1a on a background that the alternate variation also uses, you will invent a black-on-black thread list and blame 2.3.

SVG icons and the Icon Usage Analyzer

2.3 stops shipping the full Font Awesome webfont as the default icon payload. Icons become inline SVG sprites. A built-in Icon Usage Analyzer walks compiled templates, modifications, phrases, and JS controllers and keeps only the icons you actually use. Official materials describe the index payload dropping from hundreds of kilobytes to tens.

Two admin consequences:

  1. Raw CSS content: "\f019" tricks from 2.2 do not put an icon in the sprite. Use <xf:fa icon="fa-icon-name" /> (or the Less mixins the nodes article documents) so the analyzer sees the name.
  2. After upgrade, run the analyzer and rebuild caches. A child style that still emits 2.2 webfont markup will show the default bubble, a missing glyph, or both stacked.

Community write-ups still recommend Kirby’s Font Awesome Manager. That advice is from the 2.1 / 2.2 era, when the board loaded the entire Pro family. On 2.3, start with the stock analyzer. Add a third-party subsetter only if you have measured that you still need it.

WebP for uploads

When you enable it, new JPEG, PNG, and BMP uploads convert to WebP. Official 2.3 materials claim a large drop in attachment footprint once you also rebuild existing files. Treat the percentage as a direction, not a guarantee for your particular photo dump.

Do this after the board is stable, not in the same hour as the schema upgrade:

  • Turn conversion on for new uploads.
  • Run the retroactive attachment rebuild from the ACP cache tools (or CLI) when you can watch it.
  • Confirm a sample of old attachments still open, including animated GIFs you did not expect to become a single WebP frame.

Very large sources are gated by $config['maxImageResizePixelCount'] in src/config.php. Official docs mention raising it (for example to 48000000) if staff upload huge camera originals and the resizer refuses them. Raise it because you measured a failure, not because a blog said a bigger number is faster.

Passkeys

Members can register WebAuthn / FIDO2 authenticators — Touch ID, Face ID, Windows Hello, a YubiKey — on their account and sign in without typing the password. That is the 2.3 security headline members will notice.

Staff still need an escape hatch. If a user with two-step verification is locked out, an administrator can disable 2FA from that user’s User details in the ACP. Pair passkeys with the existing Security lock on the same edit screen: force a password change at next login, or force an email reset. Do not enable passkeys on Monday and disable every other factor on Tuesday. Roll them out to staff first, then to members who already have 2FA.

XenForo as an OAuth2 server

2.3 can issue tokens for external apps. Official endpoints:

  • /api/oauth2/authorize
  • /api/oauth2/token
  • /api/oauth2/revoke

Confidential clients cover server-to-server. Public clients must use PKCE. This is how you stop inventing a second password database for a WordPress companion or a custom app. It is not an excuse to point a random SaaS at your member table without reading the API scopes.

Webhooks

Setup → Webhooks sends JSON to a URL you choose when something happens — official examples include thread_insert and user_register. The payload is signed with a secret on the XF-Webhook-Secret header.

Use this when you want Discord or Slack to hear about a new thread without an add-on that scrapes the board. Do not fire a webhook to a URL you do not control. Do not log the secret in a public gist. Test on staging with a request bin you own.

Mail and cache libraries

SwiftMailer is gone. Symfony Mailer replaced it. Any add-on that still instantiates Swift_ classes will fatal the request that sends mail — often the contact form, the lost-password mail, or the activity summary. That looks like “email is broken after 2.3.” It is an add-on.

doctrine/cache is gone. Symfony Cache replaced it. Dummy wrappers exist for basic compatibility. Native code should use the new adapters. If you run Redis, expect to re-check src/config.php after the upgrade, not assume the old cache stanza is still legal.

Developer and template housekeeping

Smaller, but they bite customized boards:

  • <xf:macro name="…"> became <xf:macro id="…">. Customized templates that still use name are outdated, not “fine.”
  • Public templates get a data-template-name attribute on the outer container for logged-in administrators. Use it when you are staring at a broken layout and cannot remember which template you overrode.
  • Point releases have been touching PAGE_CONTAINER, OAUTH_CONTAINER, and OFFLINE_CONTAINER. Customized copies of those three are the first outdated-template tickets after a 2.3.x.
  • 2.3.10 added php cmd.php xf-dev:template-phraser and php cmd.php xf-dev:file-phraser for developers who still hard-code English strings.

Appearance → Outdated templates and Appearance → Outdated phrases are not optional reading. Customized files are never overwritten. They are flagged. The merge tool marks applied hunks in blue and unresolved conflicts in yellow. Merge before you invent a new extra.less patch that “fixes” a missing wrapper the core already added.

What 2.3 did not invent

Do not write a “what’s new” list that is actually 2.2.

  • Thread types (discussion, poll, article, question, suggestion) shipped in 2.2. 2.3 still has them. Configure them; do not credit 2.3 for the solution chrome.
  • The permission model is the same: Never beats Yes beats No, private nodes still zero the baseline, Analyze permissions is still the truth. The permissions article still applies.
  • Featured content is 2.3. The portal article already covers the featured/ route and the widget. Do not rebuild a magazine homepage as part of the upgrade night.
  • Enhanced search still wants Elasticsearch or OpenSearch 7.2+. 2.3 did not make MySQL FULLTEXT good enough to skip that on a large board.

If a vendor’s 2.3 sales page lists “question threads” as a reason to buy the upgrade, they are selling you 2.2.

Server requirements

Official 2.3 release notes (through the 2.3.10 line) raise the floor versus 2.2.

Piece 2.3 minimum Practical 2026 target
PHP 7.2 8.3 (8.4 is fine where your add-ons have been tested)
Database MySQL 5.7 MySQL 8.0 or current MariaDB / Percona
Search (enhanced) Elasticsearch or OpenSearch 7.2+ Same, on its own host if the board is large
PHP extensions mysqli, gd (JPEG), pcre, curl, spl, simplexml, dom, json, iconv, ctype Plus whatever your add-ons already needed (intl, gmp, zip are common)

2.2 accepted PHP 7.0 and MySQL 5.5. A host that has not been touched since 2021 will fail the 2.3 installer for reasons that have nothing to do with jQuery. Check PHP and MySQL before you download the package.

The notebook did not publish a contrasted 2.2-vs-2.3 extension list. If phpinfo() is missing gd JPEG support, you will find out when avatars stop generating — not when the upgrade wizard says “OK.”

Stage it like you mean it

Community operations notes and the official upgrade manual agree on the shape, even when they disagree on adjectives. A live, add-on-heavy board is upgraded on a copy first.

  1. Clone. Files and database onto a subdomain or a separate host. Same PHP version you will run in production.
  2. Turn cache off on the clone. Comment out Redis / Memcached stanzas in the staging src/config.php. Schema upgrades plus a hot cache is how you debug yesterday’s templates.
  3. Stock style. In the staging ACP, make the default XenForo style the guest-visible style. You want the upgrade to land on core templates, not on a 2.2 parent with 400 outdated files.
  4. Disable every third-party add-on. Not “the ones you remember.” All of them. Official and community notes both say incompatible add-ons can stop the upgrade itself, not just the front end afterwards.
  5. Backup the clone too. You will break the clone on purpose. Restore is cheaper than re-cloning from production at 01:00.
  6. Upgrade the clone with the same method you plan to use in production (one-click or manual). Time it. Read the error, not the progress bar.
  7. Only then install each vendor’s 2.3 add-on build, one at a time, and click the thing that add-on claims to do.
  8. Then import the vendor’s 2.3 style package into a new parent, keep your child, and merge outdated templates. Do not paste 2.2 extra.less onto a 2.3 parent and call it done.

extra.less in a child style is not overwritten. That is why it exists. Template modifications that search for a 2.2 HTML snippet will fail silently when 2.3 rewrites the markup. After upgrade, open Appearance → Template modifications and look for disabled or non-matching finds before you blame the style.

If the clone works for a day with staff accounts, a guest, and a brand-new Registered user, you have a procedure. If it does not, you do not have a production window. You have a vendor ticket.

Official upgrade path

Two supported ways. Same destination.

Before either one

  • Tools → Upgrade check — confirm the license sees 2.3.x.
  • Backup files and the database. The official manual is blunt: you cannot downgrade; restore is the only reverse.
  • Confirm 2.3 builds for every add-on you intend to turn back on. An add-on with no 2.3 release stays disabled, or it comes off via the ACP (never by deleting files first — orphan event listeners will fatal the board).
  • Confirm PHP / MySQL. Confirm you can open SFTP and the /install/ URL if the one-click path dies mid-download.

One-click (ACP)

If the server can download the package, Tools → Upgrade check offers the upgrade. Leave the browser tab open until it finishes. If it errors or the download times out, stop. Do not refresh five times. Switch to the manual path.

Community notes match the official fallback: when the web downloader times out, upload the upgrade package over SFTP and run /install/ yourself.

Manual (Customer Area package)

  1. Customer Area → your license → Download XenForo.
  2. Tick Download the upgrade package only. A full package is for new installs. An upgrade package is the delta you merge.
  3. Unzip locally. You want the contents of the upload/ directory.
  4. SFTP to the board root (the directory that already has admin.php and css.php).
  5. Upload the contents of upload/ into that root. Merge directories. Do not replace data/ or internal_data/. Replacing those deletes avatars, attachments, and config.php. The official manual repeats this because people still do it.
  6. The board closes itself while files are mid-replace. That is expected.
  7. Open https://your-board.example/install/ (or /community/install/ if that is your rewrite).
  8. Log in as an administrator. Finish the database upgrade. The board reopens when the wizard is done.

CLI: the official manuals in the notebook document php cmd.php xf:install for installs. They did not quote the upgrade verb. On a real server, run php cmd.php and read the command list rather than pasting a blog’s xf:upgrade from memory. If you are not already operating the board from CLI, use /install/ in a browser. A missed flag on the command line is not faster than the wizard.

Immediately after

  1. Appearance → Outdated templates and Outdated phrases. Merge. Do not skip yellow conflicts.
  2. Re-enable add-ons one at a time on the clone; in production, only the set you already tested.
  3. Import the 2.3 style package. Point the child at the new parent. Look at both variations.
  4. Run the Icon Usage Analyzer. Rebuild caches.
  5. Turn on WebP for new uploads. Schedule the historical rebuild.
  6. Create one webhook to a URL you own. Confirm a test thread_insert. Disable it if you do not need it yet.
  7. Register a passkey on a staff account. Confirm a password login still works.
  8. Send a lost-password mail to a throwaway. If it fails, look for a leftover Swift_ add-on before you rebuild Postfix.

Optional, later: $config['pageCache']['enabled'] = true; for guest HTML caching if the front page is a widget pile. Do not enable page cache as a substitute for fixing a broken add-on.

What usually looks broken first

Not a ranked official list — the notebook’s community sources do not publish a “first broken widget” table. This is the short list that follows from the compatibility breaks they do document.

Symptom Likely cause First move
Upgrade wizard fatals Third-party add-on still enabled, or cache still on Restore the clone, disable add-ons and cache, run again
Forum list OK, buttons do nothing jQuery add-on or template modification Disable add-ons until the click works; replace that add-on
Node icons missing or doubled 2.2 webfont CSS on a 2.3 SVG sprite Follow the nodes 2.3 icon pattern; run the analyzer
Layout missing header / footer chunks Outdated PAGE_CONTAINER Merge outdated templates; do not paste the 2.2 copy back
Token / tag inputs empty Select2 left behind Update the add-on or remove the Select2 modification
No mail after upgrade SwiftMailer add-on Disable it; confirm Symfony Mailer options; test lost-password
ACP or front end white-screen after you “cleaned up” an add-on Files deleted before ACP uninstall; orphan listeners Re-upload that add-on’s files, uninstall from ACP. If files are gone, $config['development']['enabled'] = true; and remove the orphan listeners, then turn development mode off
Dark variation unreadable Hard-coded hex in extra.less Check both variations; use variation-aware properties
One-click sits on “downloading” PHP timeout / allow_url_fopen / outbound HTTPS Abandon one-click; SFTP the upgrade package; /install/

A white screen after you delete add-on files by hand is the one community failure that is entirely self-inflicted. Uninstall in the ACP. Then delete files. Never the other way around.

Add-ons, languages, styles

Official compatibility, in one paragraph:

  • XenForo 1 styles and add-ons are incompatible. Uninstall them before you start.
  • A 2.2 style or language pack may be incompatible. Get a package built for the 2.3.x you are installing.
  • Customized templates are kept and marked outdated. That is a merge queue, not a preservation victory.
  • jQuery, Select2, SwiftMailer, and old star-rating scripts are hard breaks. Symfony Cache wrappers are a soft landing, not a reason to leave doctrine code in an add-on you maintain.

If a vendor has not shipped 2.3, you have three adult options: wait, replace the add-on, or accept that feature is off after upgrade. “We’ll see if it works” is how you debug production with members watching.

Keep custom CSS in extra.less on a child style. Keep vendor code in the vendor parent. When they ship a 2.3 parent, you update the parent and merge the child. That hierarchy is older than 2.3. The upgrade is when people finally wish they had used it.

Is it worth updating?

Yes, if you will actually use what 2.3 bought you.

Worth it now

  • You want one style with a real light / dark variation instead of two styles and a cookie hack.
  • Attachment storage and LCP matter, and you will turn WebP on.
  • Staff will adopt passkeys.
  • You have an external app that should use XenForo as the identity provider.
  • You are tired of a Discord bot that scrapes HTML.
  • Your add-on vendors already published 2.3 builds, and you have a staging copy.

Worth it after a wait

  • A single add-on is load-bearing (payments, a custom SSO, a directory) and the vendor’s 2.3 changelog is empty.
  • Your “style” is a fork of PAGE_CONTAINER with no child and no extra.less discipline. Fix that on 2.2 first, or budget a redesign as part of 2.3 — do not pretend the upgrade is an hour.
  • PHP is still 7.0. Upgrade PHP on 2.2, watch the board for a week, then do 2.3.

Not the reason to upgrade

  • Thread types. You already have them.
  • A magazine homepage. Build it on the version you run, then upgrade.
  • “2.2 is insecure.” Run the latest 2.2.x if you must stay. 2.3.10’s release train still shipped a 2.2.19 with the same class of security fix. Being on 2.3 does not replace backups, permissions, and not installing abandoned add-ons.

A quiet 2.2 board with three add-ons and a child extra.less can often stage and ship 2.3 in an afternoon. A gaming board with a paid theme, a server-list add-on, and a whitelist plugin should treat it as a project: clone on Saturday, staff-test on Sunday, production window on a weekday morning when you can watch mail and logins. The whitelist and server listing articles already warned you to buy 2.3-ready add-ons. The upgrade is when that warning comes due.

Do this afternoon (clone) or do not do it at all

  1. Write the inventory: PHP version, MySQL version, every add-on, every customized template, the parent style, whether Redis is on. If you cannot write it, you are not upgrading today.
  2. Confirm a 2.3 package exists for each add-on you will turn back on. Anything else stays off or gets uninstalled properly.
  3. Clone files + database to a subdomain. Disable cache. Default style. Disable third-party add-ons.
  4. Backup production and the clone.
  5. Upgrade the clone. Merge outdated templates. One add-on at a time. Both style variations. Guest + new Registered + admin.
  6. Only then book the production window. Same steps, same package, same person watching Tools → Upgrade check or /install/.
  7. After production lands: analyzer, caches, WebP for new uploads, one staff passkey, one test mail, one look at Setup → Webhooks if you actually have a destination.

2.3 is the XenForo you want to be on. It is not a Friday surprise. Stage it, merge the templates, and then enjoy the fact that dark mode, WebP, and passkeys are finally core — not another add-on you will have to upgrade again next year.