The main problem is that the state of your frontend application is in the URL. This is not flexible enough for modern UI where you might have many different zones, widgets, popups, etc. that all need their own local navigation, activation states etc. Putting all of this in a single global url is extremely hard. Designing your app so that you don't need to put it all in the global url is harder.
This problem is trivially solved by React / Vue that all provide their version of a state store that can hold the state, and make it easy as well to have elements shared or not between the tabs of your browser.
If you build your applications like phpBB forum this is not a problem, but nowadays users expect better.
There are plenty of ways to maintain state, including server store, sessions, localstorage, cookies, etc. Say you want the user to be able to customize the app layout: that doesn't need to be in the URL. Now say you provide a search functionality where the user can share the results: now your search criterias definitely should be in the URL.
It's not a black or white, one actually has to think about what the application must achieve.
> modern UI where you might have many different zones, widgets, popups, etc.
This is completely independent from the HTMX matter, but not all your application functionality has to fit one screen / one URL. There's a thin line between "modern" and bloat. Unfortunately this line is crossed every day.
> React / Vue that all provide their version of a state store that can hold the state
And many times they duplicate what's already available server-side.
> It's not a black or white, one actually has to think about what the application must achieve.
You are explaining quite well why it's hard to manage the state in a htmx app. As your app grows up all this mumbo jumbo of url, session cookies, cookies, database models becomes tangled spaghetti. You don't have to do any of this in a Vue / React app, and that reduction of complexity alone is worth the weight of those frameworks.
Something has to do this in an app regardless of what UI framework you're using. Deciding where a particular piece of state lives is fundamental to web development, and yes, URL/session/cookie/database are all valid options depending what kind of state you're storing.
Well... I don't know what to say. What you call complexity is what I consider web development 101 really. And it is well worth the price: Better user experience, better performance, less code, better adherence to standards, easier app maintenance and more.
But what did I expect ? These days web developers resort to gigantic dependencies list for the most basic things.
Notably, none of this is incompatible with React/Vue where you need it.
Hypermedia is also way better for realtime and multiplayer.
If anything where HTMX falls short is it doesn't put enough state on the backend, if anything it's not radical enough.
> You mean I should be storing the state of a popup menu in my database?
Well, if you want to present the user with a fully saved UI state even if the user closed your app and opens it later, then yes :)
Otherwise purely client side things should stay either fully client-side, or at most in session storage.
If the latency was good enough you'd store everything on the server. It doesn't force you to give them the same state when they re-open your app, you can key state by session and tabid if you want.
You define it. And the client defines it.
> If the latency was good enough
It's never good enough. Worse, it can abruptly become not good enough. And you have to code additional loading states or optimistic UI for every action that is now performed on the server and takes longer than some time.
> It doesn't force you to give them the same state when they re-open your app
Then why would you store modal state on the server?
It's also a consideration of resource utilization. A million clients with their own app state is better than a million clients hitting your server and requiring you to store that state.
Millions of users hitting the same server at the same time is a very nice problem to have. I've handled 40000r/s (script kiddies are gonna script) with 500+ concurrent users in those demos on a 5$ VPS. With all the scroll position/tab state etc not just going to the server, but to a sqlite db.
Events up are fine if you batch them and 204 (i.e CQRS). In return you get a nice pushed based system that you can throttle/batch. You only push view data when the server decides to. In my case that's every 100ms (because it's a 5$ server), so all changes in that time get batched.
>Whenever your program has to interact with external entities, don't do things directly in reaction to external events. Instead, your program should run at its own pace. Not only does this make your program safer by keeping the control flow of your program under your control, it also improves performance for the same reason (you get to batch, instead of context switching on every event). Additionally, this makes it easier to maintain bounds on work done per time period.
- tiger style https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TI...
You don't need optimistic UI, a fast server with an in process DB and a decent backend language and you'll be fine for a lot of use cases. I like to add a pop animation on the client to register something has happened, but in a lot of situations you don't even need that.
No idea what you mean
> Say you want a minimap, or a presence indicator, now
I struggle to see where I said that you have to have everything and anything on the client.
> Events up are fine if you batch them and 204 (i.e CQRS). In return you get a nice pushed based system that
That you have to actually code, create, and maintain.
> Whenever your program has to interact with external entities, don't do things directly in reaction to external events. Instead, your program should run at its own pace.
No idea what this has to do with anything I wrote
> You don't need optimistic UI, a fast server with an in process DB and a decent backend language and you'll be fine for a lot of use cases.
Again, this hinges on the childish belief that the network is always there, is always fast, and is always low-latency.
And none of these answer the question of why you would want to save "I showed a modal on the client" in a backend database.
And it's funny that you think anything about React and/or Vue is 'trivial'.
Garbage. But effective devrel.
For instance, you could entirely forgo the influence of lifecycles and global state by putting everything in a top-level Context with 1 state object that you only ever update by calling `setState`.
After that, you might find reasons to optimize your app, which could lead you to more interesting approaches like reducers or state management libraries or memoization, but I'm guessing you would never get that far and just go back to what you were doing before, since YOUR preferences are battle hardened and reliable software, while things you don't know about are only popular because of Facebook. Obviously.
What exactly are you talking about, for React? What provides "a state store"?
- Components: https://hyperflask.dev/guides/components/ - Bundling view and controller in the same file: https://hyperflask.dev/guides/interactive-apps/
I think these may be footguns though. Components for example are just a regular macros under the hood. Why not use macros then?
I'm also curious about the choice of Flask. I started with a similar approach for /dev/push [1], but ended up moving to FastAPI + Jinja2 + Alpine.js + HTMX once I figured out FastAPI wasn't just for APIs. I wanted proper async support. I love Flask, but don't you find it limiting?
It reminds me of how PHP development used to be back in the day. That's not meant as a bad thing, I always liked how simple it made the development process for the right size project.
Having migrations, static files and templates for one aspect of a project all grouped together is so useful and I didn't realise until I didn't have it.
That, or just use Airtable as a backend, if you can get away with it.
Mostly I agree with you though, I got swept up with lots of "recent tools & frameworks" projects and I really miss the Django admin. Django+HTMX has always seemed like a tempting option.
I feel like Go is quite verbose and defining templates in Templ feels painful.
there's a performance increase too, but these apps I'm talking about are so simple it's not enough to really notice. objectively FastAPI is really good and makes running a simple site so easy, I'd still recommend to most people using that.
I was expecting something like what FastHTML does where htmx is essentially built in.
However, the project itself looks great. I love Htmx, although I have to admit I started looking at Datastar recently.
new WarpSpeed("warpdrive", { "speed": 20, "speedAdjFactor": 0.03, "density": 2, "shape": "circle", "warpEffect": true, "warpEffectLength": 5, "depthFade": true, "starSize": 3, "backgroundColor": "hsl(224,15%,14%)", "starColor": "#FFFFFF" });
https://www.jetbrains.com/guide/dotnet/tutorials/htmx-aspnet...
It's inspired by Astro Pages [1] which are the same thing in the javascript world. I really liked the developer experience working with them.
[0] https://htmx.org/essays/locality-of-behaviour/ [1] https://docs.astro.build/fr/basics/astro-pages/
And most apps don't need crazy scale, they need simplicity.
I've been thinking about Flask and Quart pretty much interchangeably for awhile now and use Quart for Python backends. For those who aren't aware Quart is the async Flask and they share system internals, it is usually easy to use something created for Flask for Quart.
Assuming that non-blocking sockets require a special language syntax that breaks seamless compositionality of functions is a lack of fundamental knowledge. No wonder you refer to the industry adoption (crowd opinion) in your next sentence, instead of applying the first-principles analysis. In 2025, the expectation is that you should've at least tried learning how Project Loom is implemented, before venturing bold opinions on the async keyword in Python: https://openjdk.org/projects/loom/
> The only way to scale a flask API is to use gevent, which is just problems waiting to happen.
This is FUD.
[1] https://www.xmlui.org/ [2] https://docs.flightphp.com/en/v3/
Yeah, there's a lot of dependencies here - like a dozen other Flask extensions. When I saw this, I was excited about the component system, but it's too bad that it's so far from just being Flask and HTMX.
The component system is not fully independent because it depends on multiple other extensions but it mostly is as this extension: https://github.com/hyperflask/flask-super-macros
On the GitHub organization there is a list of all the extensions that are built as part of the project: https://github.com/hyperflask
I got most excited about sqlorm (https://github.com/hyperflask/sqlorm). It is way too early to feel comfortable adopting this, but I really like the concepts. I use pydantic a lot, I would love to see the SQL as docstrings as a pydantic extension. I get tired of writing serializers everywhere and would prefer to have a single pydantic model to reference throughout my codebase. Primarily I use Django, but these days am using less and less of the framework batteries outside of the ORM.
I've also submitted SQLORM on HN if it's of interest to others: https://news.ycombinator.com/item?id=45607688
A fast cycle time is key when working with LLMs because they are good at adjusting to errors but bad at getting things right first time. So I like the HTMX-based stack.
plain keep the admin dashboard and is very agent friendly
I'll definitely keep an eye on it until it hopefully matures.
Why is this? Do larger teams have time for busywork that they can't fill with HTMX?
In reality, people ended up having to deal with weird bugs because asynchronous Python isn't the most ergonomic, while having negligible to zero performance improvements. Proof that most people are terrible at choosing tech stacks.
Then, AI came into the scene and people were building APIs that were essentilly front-ends to third party LLM APIs. For example, people could build an API that will contact OpenAI before returning a response. That's where FastAPI truly shined because of native asynchronous views which provides better performance over Flask's async implementation. Then people realized that can can simply access OpenAI's API instead of calling another front-end API first. But now they're already invested in FastAPI, so changing to another framework isn't going to happen.
Either way, I like FastAPI and I think Sebatian Ramirez is a great dude who knows what he wants. I have respect for a person who know how to say no. But it's unfortunate that people believe that Flask is irrelevant just because FastAPI exists.
That is an understatement. I loathe working with async Python.
> For example, people could build an API that will contact OpenAI before returning a response. That's where FastAPI truly shined because of native asynchronous views which provides better performance over Flask's async implementation.
TO be fair there are lots of other things that require a response from an API before responding to the request and therefore async reduces resource usage over threads or multi-process.
Agreed. However, these are rare and many people have been abusing asynchronous views instead of delegating the task to a background worker when multiple external requests are required. Showing a spinner while polling a synchronous view is dead simple to implement and more resilient against unexpected outages.
Versus FastAPI which is lead by a single maintainer which you can search back on HN about opinions on how he's led things.
Flask also has at time of writing only 5 open issues and 6 open PRs, while FastAPI has over 150 PRs open and 40 pages(!) of discussions (which I believe they converted most of their issues to discussions).
Lastly on the technical side, I found Flasks threaded model with a global request context to be really simple to reason about. I'm not totally sold on async Python anymore and encountered odd memory leaks in FastAPI when trying to use it.
https://luolingchun.github.io/flask-openapi3/v4.x/
> dependency injection
While nice I never found this to be a critical deciding factor of using a technology.
> real async
If you really want it there is Quart which is real async
https://github.com/pallets/quart
I'm not a huge async fan in python anymore so not it's not a huge issue for me. But there are definitely options for Flask if you want to use async.
It's possible between Quart and svcs (for DI) and some Pydantic/Marshmallow/OpenAPI extension you might be able to mimic what FastAPI does. But I'd just use FastAPI. I use async too. It's a lot easier to scale in my opinion.
Do none of these pieces matter to you? Like do you not do any data validation or care about OpenAPI?
It's the "choose boring technology" poster child, of sorts: get things done reliable, without using any design younger than 15 years ago.
https://www.sequoiacap.com/article/partnering-with-fastapi-l...
I made an announcement post here: https://hyperflask.dev/blog/2025/10/14/launch-annoncement/
I love to hear feedback!
this looks awesome!
I use sqlalchemy daily, it's an amazing library, but I wanted something more lightweight and straightforward for this project. I find the unit of work pattern cumbersome
it's called "sqlalchemy core"
https://docs.sqlalchemy.org/en/20/core/
Although nobody seems to use the term ORM correctly any more so it's entirely possible that neither is peewee or sqlorm.
The story behind why ORM is nowadays no longer used correctly is kind of funny:
1. Query generator sounds primitive, like cavemen banging rocks together. Software engineers are scared of primitive technologies because it makes their CVs look bad.
2. Actual ORMs attempt to present a relational database as if it was a graph or document database. This fundamentally requires a translation which cannot be made performant automatically and often requires very careful work to make performant (which is a massive source of abstraction leaks in real ORMs). People don't realise the performance hit until they've written a chunk of their application and start getting users.
3. Once enough people encountered this problem, they decided to "improve" ORMs by writing new "ORMs" which "avoid" this problem by just not actually doing any of the heavy mapping. i.e. They're the re-invention of a query generator.
It is still basically a query generator, just with the helpful step of converting selected tuples into objects, and tracking changes to those objects. This means that it is often possible to solve ORM-related performance issues without too much work.
It’s been a long time since I worked with SQLAlchemy though (or even touched Python), so my memory or knowledge of the current ecosystem might be off.
I am sure that many will like the blend of Python and Flask - and with server side HTMX I know that components are a key aspect
plus you website doesn't hurt my eyes like FastHTML
---
here's my comparison to https://harcstack.org
So, I think you have a much wider audience with a very popular set of options - for comparison HARC stack makes more "out there" choices which I hope will appeal to the small group of folks who want to try a new way to go - like the idea of functional code for HTML (think elmlang on the server side) and are a bit allergic to Tailwind denormalization.Notable sub-projects that could be used with Django:
- https://github.com/hyperflask/jinja-super-macros
- https://github.com/hyperflask/jinjapy
Would check it out asap!
Everything is rendered server-side, with sprinkles of modern JS where needed or useful, powered by some JSON-serving routes in the same flask app. A CSS framework on top to make it look good.
Basically more or less how we built web apps 15 years ago. :-)