htmx 4.0: What Breaks, and How the Release Avoids Breaking You
htmx 4.0 makes inheritance explicit and swaps error responses, but the real lesson is the rollout: latest stays on 2.x, a checker ships, and key behaviors get revert flags.
Umut Korkmaz
Published: 4 min read
On this page6
htmx 4.0.0 was released on August 28, after what the team describes as eight months of work. The headline changes are real: attribute inheritance is now opt-in, event names follow a new scheme, history no longer caches pages in localStorage, and the internals moved from XMLHttpRequest to fetch(). What caught my attention, though, is how carefully the release is staged.
What changed
The announcement says that from a user's point of view htmx 4 is almost identical to htmx 2, with three major changes:
- Inheritance is explicit. In htmx 2, an attribute like
hx-confirmon a parent applied to its children. In htmx 4 you have to say so with a suffix:hx-confirm:inherited="Are you sure?".hx-disinheritis gone because it is no longer needed. The team calls this the largest upgrade burden. - Events follow
htmx:phase:action.htmx:beforeRequestbecomeshtmx:before:request,htmx:afterSwapbecomeshtmx:after:swap, most error events collapse intohtmx:error, and HTTP errors firehtmx:response:error. Thehtmx:xhr:*andhtmx:validation:*events are removed. - History re-fetches. On back navigation htmx fetches the page again and swaps it into
<body>. The oldlocalStoragesnapshot could hold DOM changes made by third-party scripts whose logic was gone after a restore. Anhx-history-cacheextension restores fromsessionStorageif you still want caching.
On the new side there are built-in morph swaps (innerMorph and outerMorph, based on idiomorph) and an <hx-partial> tag that targets several elements from one response, as a clearer alternative to out-of-band swaps.
The changes that fail quietly
The What's New in htmx 4 guide lists more breaking changes than the announcement. In these, nothing obviously breaks; the app just behaves differently:
- htmx 4 swaps all HTTP responses except
204and304. If your server returns an HTML error page with a 422 or 500, it now lands inside the target. htmx 2 did not swap 4xx and 5xx responses. - The default timeout is now 60 seconds. htmx 2 had none.
hx-deleteno longer includes the enclosing form's inputs. The guide's fix ishx-include="closest form".- Out-of-band elements now swap after the main content, not before it.
hx-disablebecomeshx-ignore, andhx-disablenow does whathx-disabled-eltused to do. The guide says to do thehx-disablerename before upgrading, and before renaminghx-disabled-elt.
The sample upgrade checker output on the announcement page shows the nastiest case. An hx-headers attribute on a parent that carries a CSRF token no longer reaches child elements without :inherited, so the server rejects the request. In your logs that will probably look like a CSRF or auth problem, not an htmx problem.
The release mechanics are worth copying
lateststays on 2.x. The 4.0 line is taggednexton npm until some point in early 2027, because the team does not want to force-upgrade people who load htmx from unversioned CDN URLs.- A checker ships with the release.
npx [email protected] upgrade-check -- ./templatesreports missing:inheritedsuffixes, renamed and removed attributes, old event names and removed API calls, with file and line numbers. - The riskiest behavior changes come with revert switches.
htmx.config.implicitInheritance = true,htmx.config.noSwap = [204, 304, '4xx', '5xx']andhtmx.config.defaultTimeout = 0, plus anhtmx-2-compatextension that restores htmx 2 defaults and event names. Thefetch()move is explicitly marked as not revertible. The guide lists no flag for the out-of-band ordering change. - htmx 2 stays supported indefinitely, so there is no deadline pressure.
- There is an upgrade skill for LLMs,
htmx-upgrade-from-htmx2, alongside guidance and debugging skills.
Put together, a team can move one behavior at a time, with a tool that knows the exact list of breaking changes. When I think about a future breaking release of my own packages, like Meridian on NuGet, the checker and the per-behavior flags are the two ideas I would copy first. A changelog tells people what changed. A checker tells them where it touches their code.
What I would check on Monday
If a team runs htmx 2, this is my list:
- Find unversioned htmx script URLs and pin them to an exact version.
latestis safe for now, but only until early 2027. - Run the checker on a branch. The default scan covers
.html,.php,.js,.ts, Jinja, ERB and Handlebars files. Razor views or other template types need--ext, for example--ext .cshtml. - List every endpoint that returns HTML on a 4xx or 5xx and decide what should happen: design it as swap content, route it per status with
hx-status:422="swap:innerHTML target:#errors", or keep the old behavior withnoSwap. - Grep your JavaScript for old event names. The checker looks in
hx-onattributes and in scripts where it can, but custom event wiring deserves a manual pass. - Look for slow requests, such as exports and reports, that can run longer than the new 60-second default timeout.
My take
htmx 4 is a reasonable major version, but its release engineering is the better lesson. Keeping latest on the old line, shipping a checker and giving the riskiest behavior changes their own revert switches turns one risky migration into several small ones. And since htmx 2 is supported indefinitely, the right first step for most teams is not the upgrade. It is pinning the version and running the checker, then planning the upgrade.
Sources
Primary references used for this post.