Pretty much every experiment I build now starts with Go, htmx, and SQLite to keep things simple and fast but still responsive.
I put a few more thoughts about this here:
https://housecat.com/blog/the-hugs-stack-hypermedia-unix-go-...
I looked into this when I tried HTMX 4 on a project earlier this year. I actually found that https://alpine-ajax.js.org/ was smaller than HTMX while providing all the features I needed. It is one of the sanctioned projects they link to so I felt good using it
I have enjoyed working with htmx very much.
I'm still skeptical of htmx being the foundation for a 100-year web service, but I think this is a really worthwhile goal. I'll add that aside from static HTML, I don't have a better option.
Nonetheless I hope all who do use Htmx, enjoy using it.
Looks like some copy is missing here
For what? Don't leave us hanging!
In fact, I find Django and Postgres to be the best solution for htmx but Go stack is probably almost as good in terms of developer velocity and obviously much faster. So I think that's a good solution.
You can really build powerful production apps with htmx, and what people underestimate is how good it is with AI assisted development (Claude understands it and does it well, and if any JS glue logic on a specific template is required, it's pretty well written and not a mess).
One is a programming language used for writing client side code, and the other is a minimal library that makes server sent documents more ergonomic. Yes, it's a JS library with a few nice conveniences, but the main draw of HTMX encourages a completely different app architecture than what the average dev would arrive at with plain JS.
They're just two different things to me, and so it seems irrelevant if LLMs can help you write one faster. If you're only using HTMX to avoid JS, I don't see how LLMs discourage you from doing that. Wouldn't it be better to vibecode something you have an easier time reading than vibecode a language you don't even understand enough to use? What are you going to do if it blows up?
Perfect is the enemy of good and all that. If something is useful, it’s possible to fix the architecture later. The only counter-example I know of has been GitHub, which was built on RoR and so poorly planned that it’s still biting Microsoft on a regular basis.
Full Disclosure, I am CEO of HTMX
This is not a criticism but I suspect that the people enjoying HTMX are either people preferring old-school server-side rendering or react users.
Just sharing my experience, because HTMX is the absolute darling of hacker news.
Since i mainly develop real SPA, i found that is more complex than just using typscrpit if you build something non-trivial as managing state on the server is not fun at all.
In my opinion if you are happy using angular, you'll find that HTMX is a step backward in terms for dev experience. Can't speak about react, but since it is not a battery included stack unlike Angular, i can understand why many people find they'd be better off moving things server-side instead of messing around with 15 third-party libraries. My 2 cents
Better than htmx IMO.. Same author.
For pushing updates, we use ActionCable, but we do it in a different way from what we used to do with Turbo Streams: when a record is updated, instead of sending HTML from the server to the client with instructions on what to replace, we only send a small JSON payload with the ID of the element that was updated. On the client side, an event is dispatched that any DOM element with <hx-trigger="<resource-id>:updated from:body"> will trigger on. For the rest it's just basic HTMX, only the trigger is "custom".
That doesn't mean do dumb / complicated / bloated stuff for no reason. If the best thing for your users is static html, use that.
"let us rething how extensions can and should work,"
I think you meant rethink here.
And if you do, why start with a simpler framework?
If you have 1/5th the context to consume, that's going to generate better code than the comparable typescript, even if the language is an esoteric one.
I'd expect it to be the other way around: LLMs will increase HTMX(and similar solutions) adoption because alongside of being excellent at writing HTMX there are also excellent writing web components.
React, vue and similar still have their use case, but htmx + web components can drive you really far.
The advantage for the LLM is the same for humans. With the right abstractions, code can be written quicker and more robustly.
To get more hands off with LLMS you really want to have a lot of engineering rigor. A big part of that is a focus on tests. If your abstractions make testing easier, your results will be a lot better. For Javascript the more you can test logic without DOM manipulation and without playwright tests, the better.
I found LLMs to be default to and be pretty good at working with HTMX, but not great (mostly lots of state synchronization issues). The focus on DOM markup of HTMX does not lend itself well to simplifying testing. I don't claim to be an expert at HTMX, but I don't see a separate section on testing in their documentation.
I am trying out the foldkit framework because it makes a lot more testable outside the DOM. Its probably too heavy weight for most humans (and for simple apps- it only seems appropriate for client-side apps), but I will see how well LLMs can work with it.
Disagree. The RoR front end was way more stable and usable than the mess they have made now.
They love htmx! Claude will independently suggest using it instead of more general js frameworks for smaller projects. A gpt model told me, and I wrote this down because it was striking, "htmx won the argument it was making."
It's the same thing with rust. I'm an ocaml expert and ocaml genuinely fits a lot of the problems I work with better regardless of that. But because of when the models were trained and what they were trained on, a certain sort of alt-consensus opinion is frozen into them, and it believes rust is a better choice for nearly everything!
I think you're good for the next few years at least. It's an open question what happens after that dead internet theory recursive loop of llms trained on llm output etc so who knows you might be good forever.
You mean generate unmaintainable JavaScript for us.
> Full Disclosure, I am CEO of HTMX
i think you've found a good job!
Skill.md here: https://github.com/dunctk/rasx-app-framework
That's on you not on your platform
Do you not have a database for your backend? Managing state is kind of their thing.
Then HTMX is to them what the micro-ORMs were for me (and, if you've been in .Net for a couple of decades, I suspect you too).
(Congrats on the release)
Really? I've never found that difficult. Sessions exist, URL parameters exist... Perhaps in a complex SPA you can have trouble, but so many of the "applications" I've worked on are just glorified documents.
Here’s the thing: there’s still a place for HTMX. Lots of places. But “building an SPA but not actually and SPA” is not a lane for HTMX. Nor do they promote HTMX for that purpose. Really quite the opposite.
Different tools for different jobs. (Me? I honestly love React, just a more minimal stack. Zustand and TanStack and Vite. No Redux or Next.JS)
Seriously DB->json->client->toHtml
DB->toHtml->client
Just imagine if that html wire format also conveyed the interactivity too and you eliminate the issues. And you can always seperate whatever concerns you want in whatever tpl lang of your choice.
Also htmx 4 is kinda just an worse datastar funnily enough In it's own way.
The htmx team is very happy to announce the release of htmx 4.0.0! This is the culmination of 8 months of work (plus a game) and we are very happy with the results.
The idea of htmx 4 started to germinate when I decided to create fixi and, in doing so, got more familiar with the fetch() API and async programming in JavaScript. (htmx had always used XMLHttpRequest due to backwards compatibility issues.)
One chance evening I was contacted by Christian, who had some interesting ideas around streaming HTML that got me thinking that moving the internals to fetch() would simplify things for him and for the library in general.
After a bit of work I managed to get Michael and Alex on board, and we were off to the races.
Development has been very smooth. We started a port of fixi + the htmx test suite. Over time, we rediscovered why htmx did many of the things that it did and moved our new implementation closer and closer to the old one. At this point the behavioral differences between 2.x and 4.x are relatively small and where they do diverge we have made explicit choices that we feel will put htmx-based applications in a good spot for being 100-year web services
Note that we are not marking 4.0 as latest in NPM because we do not want to force-upgrade users who are relying on non-versioned CDN URLs for htmx. Instead, 2.x will remain latest and the 4.0 line will remain next until some point in early 2027. The website, however, will reference 4.0.
As mentioned above, htmx 4, from a user’s viewpoint, is almost identical to htmx 2. There are three major changes:
localStorage by default (which was a cause of many support headaches). Most people won’t notice this at all.Internally, we migrated from XMLHttpRequest to fetch() but that should be transparent for most users of htmx.
In htmx 2 many attributes were “inherited” by default. This allows you to place attributes on parent elements and their behavior will apply to child elements. This behavior, which came from the intercooler.js days, was inspired by CSS and, unsurprisingly, worked out about the same as CSS: powerful but difficult to understand at times.
In htmx 4 attributes are not inherited unless you explicitly say so by adding an :inherited after the attribute name:
<!-- htmx 2 -->
<div hx-confirm="Are you sure?">
<button hx-delete="/item/1">Delete</button>
</div>
<!-- htmx 4 -->
<div hx-confirm:inherited="Are you sure?">
<button hx-delete="/item/1">Delete</button>
</div>
This will be the largest upgrade burden in migrating from htmx 2 to htmx 4. To make things easier, we have provided a command line tool to find places you need to mark as inherited.
Note that attributes like hx-disinherit, etc. are no longer required and should be removed.
The events triggered by htmx 2 had grown organically over the life of the library and were not particularly well organized, making it difficult to know exactly which event was fired when.
In htmx 4, all events now follow htmx:phase:action[:sub-action]:
| htmx 2 | htmx 4 |
|---|---|
htmx:beforeRequest |
htmx:before:request |
htmx:afterRequest |
htmx:after:request |
htmx:beforeSwap |
htmx:before:swap |
htmx:afterSwap |
htmx:after:swap |
htmx:configRequest |
htmx:config:request |
In addition, the following changes were made:
htmx:error. HTTP error responses fire htmx:response:error.htmx:xhr:* events are removed. htmx 4 uses fetch().htmx:validation:* events are removed in favor of native browser form validation.The full table is in What’s New in htmx 4.
The command line upgrade checker flags old event names in hx-on attributes and in your JavaScript where it can find them.
History support has always been included in htmx, allowing you to implement back-button aware actions with simple attributes. In htmx 2, a cache in localStorage was used to snapshot pages for restoration. Unfortunately a large source of issues was that this snapshot could include DOM mutations by 3rd party JavaScript libraries. When the page was restored, those mutations remained but the underlying JavaScript logic was not.
htmx 4 does not cache pages in localStorage. On back navigation htmx re-fetches the page and swaps it into <body>, or into the [hx-history-elt] element if one is present. This allows 3rd party JavaScript libraries to “just work” in most cases and, with good request caching, is very fast.
If you want local caching instead, we now ship a very complete hx-history-cache extension that restores history from sessionStorage and is designed to integrate well with scripting solutions like Alpine.js, etc.
There are two big new features in htmx 4, both of which we are really excited about:
We now support morphing swaps out of the box with htmx. I created idiomorph and nearly included it in htmx 2.x but decided against it. In htmx 4, Michael has done great work improving on that algorithm and integrating it seamlessly into htmx.
<hx-partial>Another major new feature is the <hx-partial> tag. This tag is similar to out-of-band swaps, but is much clearer when you want to do something beyond just replacing a single element with a new version of itself:
<hx-partial hx-target="#messages" hx-swap="beforeend">
<div>New message</div>
</hx-partial>
<hx-partial hx-target="#count">
<span>5</span>
</hx-partial>
Much of the excitement in htmx 4 is in the extensions. Switching to fetch() internally let us rethink how extensions can and should work, and sparked the creation (and recreation) of many new extensions, for example:
hx-preload - preload content (e.g. on mouseover) to speed requests uphx-download - native, fetch-based file downloadshx-alpine-compat - smooths over compatibility issues between htmx and Alpine.jshx-history-cache - caches history in sessionStorage, provides Alpine.js compatibilityAdditionally, there are three new or updated streaming HTML extensions:
hx-sse streams over text/event-stream.hx-ws streams and sends over WebSockets.hx-multipart streams over multipart/mixedFinally, we decided it was time to try our hand at our own small front-end scripting solution that tightly integrates with htmx. hx-live is inspired by Alpine.js, jQuery and hyperscript, and makes front end scripting pleasant and fun. It even supports what we are calling DOM-based, HATEOAS-friendly reactivity.
There is a new htmax.js bundle in the distribution which packages htmx with the most popular of these in a single file if you don’t want to think about which ones you want to pick.
For a complete upgrade guide see What’s New in htmx 4.
As mentioned earlier, we are providing an upgrade tool to help you:
$ npx htmx.org@4.0.0 upgrade-check -- ./templates
File extensions: .html, .php, .js, .ts, .jinja, .jinja2, .j2, .erb, .hbs
Use --ext to add more (e.g. --ext .vue --ext .svelte)
Scanning 1 file(s)...
Found 8 issue(s) in 1 of 1 file(s).
templates/index.html:1: [inheritance] hx-headers needs :inherited suffix (descendant on line 3 has hx-delete) (this looks like a CSRF token; without :inherited the header does not reach child elements and the server rejects the request)
templates/index.html:2: [inheritance] hx-target needs :inherited suffix (descendant on line 3 has hx-delete)
templates/index.html:2: [inheritance] hx-confirm needs :inherited suffix (descendant on line 3 has hx-delete)
templates/index.html:3: [renamed-attr] hx-disable -> rename to hx-ignore (hx-disable now means 'disable during request')
templates/index.html:4: [removed-attr] hx-vars is removed -> use hx-vals with js: prefix
templates/index.html:4: [removed-attr] hx-prompt is removed -> load the hx-prompt extension to keep the same syntax
templates/index.html:9: [old-event] old event name "htmx:afterRequest" -> "htmx:after:request"
templates/index.html:9: [old-api] htmx.addClass() is removed -> use element.classList.add()
We are also shipping an agent skill to assist in upgrading
htmx 4.0 can be installed via a package manager referencing version 4.0.0, or can be linked via a CDN:
<script src="https://unpkg.com/htmx.org@4.0.0/dist/htmx.min.js"></script>
or Downloaded
Like it or not, a lot of people are using LLMs and we are providing the following skills files for LLMs:
htmx-guidance - core htmx skills for developing with htmx 4htmx-debugging - diagnosing htmx issues during devhtmx-extension-authoring - writing and debugging htmx 4 extensionshtmx-upgrade-from-htmx2 - migrating a codebase from htmx 2.x to 4.x(Let’s leave aside if releasing a new version of a library in the LLM era is a good or bad thing!)
We hope you enjoy htmx 4. htmx 2 will continue to be supported indefinitely so don’t feel any pressure to upgrade.
I’d like to thank the following people for all their help with this release:
Wouldn’t be an htmx update without upgrade music:
I let the llm write components which are independent to each other. This works great and keeps everything clean. The times that llm would only generate unmaintainable code are long gone with OPUS, Fable and sol 5.6
All the stuff I lost in training data I gained back in having great compiler feedback.
I don't think agents are nearly as restricted by language or training data as we think.
I'm not sure why so many people seemingly fall into the trap of trying to find one tool and then use that absolutely everywhere. I mean, I'm familiar with it as in "it's fun" as I used Nix as a framework for a static website builder, but I keep seeing people making those sort of choices professionally too. Like when React first became popular, then suddenly people try to jam it into absolutely everything, until they slowly walk back and then after some years agree that maybe it's good for some things, not for everything and not as a default.
RoR is the only framework I’ve ever heard of being so bad that it killed startups. I personally know of two that were doing well, but RoR was so brittle and slow that they couldn’t hire enough to keep it going. This is compounded by Ruby devs being pretty rare.
Thank you for your kind words!
This is Hacker News. This is exactly the place to tell people they’re overanalyzing and should just build something.
And, yeah, HTMX is truly great for sites with limited interactivity. You really, really do not want or need a full React Leaning Tower of Pisa stack for a simple presentational website.
> You can put it on your LinkedIn, because it’s true.
I only take LinkedIn seriously under extreme protest, so this is extremely tempting.
This is such a "poor carpenter blaming his tools" take.
RoR isn't holding you back from writing performant, high-quality code. However, letting inexperienced developers run wild without supervision does end up with a codebase committing most of the deadly sins of software: (1) proliferation of competing patterns (2) proliferation of competing third-party libraries, leading to more #1, (3) inadequate test suite, and (4) an app that serves up so many 500 errors that you can't tell which are new and/or which indicate a problem. #4 is definitely more common in untyped languages, since that whole class of bugs can't be caught at compile time.
By the time a lot of these "startups" get to the mature state they have like a 7-year-old codebase that is beyond help. But you can use Ruby and Rails responsibly. I've seen it done. Usually all that's needed is to apply yourself to understanding how to cache, and then, identifying the key expensive high-traffic endpoints and converting them from ActiveRecord N+1 messes into single-query eager-loaded beasts, sometimes skipping ActiveRecord's object instantiation. Sounds scary, but it's inevitable for a popular application on any language/framework that you'll need to go beyond the tutorial-grade code for key transactions. This kind of thing is what Staff Engineers are for.
It's just about all Twitter links, where's XCancel/Nitter when you need 'em :(
Please take a look at the official documentation for htmx, which specifically clarifies that the author owns many hinges.
Absolute madman.