- I'm pretty smitten with Phoenix as a framework. A lot is built into the BEAM by default and the Elixir ecosystem is quite lovely.
I've been building an Etsy-lite replacement in my free time with it: https://plukio.com/
It's pretty enjoyable. I also like using Ash for data modeling and business logic expression. It's also quite lovely.
- I wanted to try out Erlang + Elixir since forever, do you think Phoenix LiveView would be a good starting point? For example, to create something like a simple game with modest persistence and only very limited RT-features? I was thinking about sth like a quiz app, not a web MMORPG of course :)
Or is LiveView only useful to optimize partial page reloads and SEO?
- LiveView is perfect for that. one of the easiest to understand demos of it is actually something just like that.
that said liveview is capable of 60fps server-rendered animation, so it's definitely not just for speeding up page loads.
- Thanks a lot! I'll give this a try next time I feel like coding for a hobby.
I've tried exactly this "project idea" in a half-assed way some time ago with next.js, Postgres and Prisma before I was out of free-time-in-front-of-computer.
Then abandoned it again it when I started coding for a living again. It was exactly the "modest RT capabilities" thing when I abandoned it. Because I started using Firebase (2023, Supabase was not known to me then) and then I felt like "OK, I managed to get full next.js running properly on shared hosting with limited server-side JS, but now I again need an external cloud provider for a hobby project" (Firebase).
I read a bit about their pricing models and lost interest.
I think next time I'm gonna try see what this stack can do.
In 2024, I heard a very interesting conference presentation about Erlang and its concurrency model, that was after the hobby experiment, and made me want to revisit losely functional languages with strong pattern matching (OCaml too, but that's a different topic).
- I've been using Phoenix for super basic things for a very long time since I first discovered it at the Elixir meetup in ATX.
I haven't touched it in a while, Since writing code these days, as most of us know, it's basically steering an LLM.
So I wonder how good are LLMs at writing Phoenix or Elixir so to speak? Time for me to create another side project... and figure it out.
- It works great for a number of reasons
- it’s functional making it much easier to reason about for LLMs (eg no side effects)
- it’s compiled (including the html template), so the LLM get instant feedback if something is off and can fix it quicker
- it’s more concise than other frameworks (language, framework, no front/backend split) and consequently you hit the max token limit much less frequently
- it has excellent tailwind support
I told a business partner to just use claude for certain tasks a year ago, and it failed miserably in python where it succeeded in elixir/phoenix liveview. This was a regular occurrence. LLMs have obviously progressed since, but the principle still stands that they work much better in elixir than python.
So in short: it’s great and arguably better than most other languages and frameworks
- LLM use is very solid here. I have been shipping some fairly cool stuff for different clients, just like if I was managing a team of 3 or 4 people.
The stable nature of the language, and the static/immutable nature of constructs, presumably really helps moving safely here.
- I've built several production quality, mid-sized apps in Phoenix/Elixir over the last year using Claude Code (CC). In my experience, it's great, I had better results with this stack than I had with Django when using purely CC. It's token efficient (because of code generator), has great static analysis, and terse (because functional). Phoenix even generates an Agents.md The apps themselves are highly scalable and look great.
Checkout https://github.com/oliver-kriska/claude-elixir-phoenix (not me).
- Pretty good as others have mentioned. Even more so when one starts adding packages like credo, ex_slop, and boundary to run deterministically and steer the LLM.
Don’t like a pattern that LLM introduced? Write a custom credo rule and the problem doesn’t come back.
- It’s exceptional. We’ve improved throughput on new features by about 2x and sentry errors are down. Our codebase is 2-300k loc and pretty old in some places, I’ve been really impressed with just sonnet.
- I'd argue that it's one of the best, especially with Tidewave:
- Worth checking out...
- They were pretty good a year ago, so I am sure it is even better than that now.
- I like this familly of technologies. Having an SPA-type app that's mostly backend.
Recently i've redone my app website (https://alt-tab.app), and I implemented a minimal spa.js that has a similar approach. I find the end result blazing fast, simple to maintain / reason about, few moving pieces. I used Early Hints, compressed every single thing, inlined CSS, etc. I don't know how i could even make it faster.
I recommend this approach for websites that are not very complex. Of course if i made a browser-based music player with a super dynamic UI, that would have been a different story~
- Can't the website be literally static HTML for 99% of it? I don't really see any user defined input that would change the output.
It's really fast, and seems fine, but is it just static pages? If not, why not. That's the question most front end devs don't ask themselves enough.
- I think it seems logical on paper. I tried it, and it feels perceptually way worse. It also think it's objectively slower.
When you go from HTML page to HTML page without JS, the browser starts from scratch on every page. The user gets a big flash, then the browser has to redraw the page from scratch. It's actually a lot of work often.
If the browser expected pages to be similar, and added optimizations to reuse existing content, essentially doing internal SPA work, that would be a different story. To my knowledge, the browser does no such optimization, and brute-forces renders every URL from scratch.
You can actually try for yourself on the website I linked. Chrome devtools > disable Javascript. It's a pretty good experience still since I optimized everything. However, you see all sorts of things flicker and move around. It's not the smoothest experience. And If you have worse Internet, it gets worse and worse as you see more of the tear-down > built-up on every click. With the SPA experience, if you have bad internet, you can still scroll around and use the page, as you wait for the update to arrive.
Of course, you're totally right that static HTML works pretty good when the website is already simple and fast. My point was that with 4KB-uncompressed / 140LoC, I can get the smoothest experience. And I unlock options later on like having loading spinners for example.
My general point was that you can do simple client-side rendering in 140 LoC. You keep a simple backend-served website, and add a little polish this way to have a smooth experience.
I find it very cool to have polished app-like experience, while having a simple backend to serve. I like the low-tech, few moving pieces, yet I get options for great UX if I want.
I got charmed by this path with LiveView and Hotwire back in the day. I'm thankful that people continue to push this approach. It's wonderful
- > I don't really see any user defined input that would change the output.
I feel like the distinction between static websites and SPAs has been lost in the last decade, despite it being in the name _single page application_.
The point of SPAs is not "it's more interactive than a static website is", but "I don't need to fetch the new page and wait it to load as I navigate". You can have any custom behavior just by adding JavaScript. That's something we have from 30+ years.
"applications" don't interrupt the user as you navigate, and we tried to replicate that on the browser, by having history and render JavaScript controlled.
- > each navigation had to reload the whole page
Saving the world, 50ms at a time.
Honestly there are times when using the View Transition API makes sense, but the context here is a dinky brochure site. The weight of scripting does as much damage to first load as it saves on subsequent loads. Browsers are good enough at managing this stuff themselves.
- For those of you a similar SPA-type app with more type safety – which is even more useful for writing code with AI – you may want to have a look at the Gleam language and the Lustre web framework [1]. It combines the best of Elixir and Elm. You can mix and match having more logic in the backend or the frontend, as Gleam compiles both to Erlang and to JS.
- Very cool concept with AltTab. Have always been looking for something like it!
- Oh, the alt tab developer! I actually love your product.
- Dude thank you for making AltTab. Recently you've introduced the pro version and paywalled some features behind it. That's totally fine and I bought the pro version but my honest 2c for you is...25 bucks for a window switcher app seems too high. Please make it 15 or less. Thanks
- LiveView is such a breath of fresh air, especially over the vibe coded NextJS rats nests that have become the norm (that need specialized hosting, are dog slow and require a ton of proprietary paid services bolted on like caching, background workers and even auth which Elixir and Phoenix provide out of the box).
- I've been loving LiveView. Been using it for a project for a client recently and it's so... chill. I like it a lot.
- What caching is provided out of the box for Phoenix framework?
- Doesn't seem to be mentioned in the page but if you're talking about request caching there's libraries like PlugHTTPCache or RequestCache.
Otherwise I usually use Nebulex (annotations are nice for Ecto queries) with ETS as it's faster than with Redis (if you don't care about losing the cache on deployment).
- Out of the box in Elixir/Erlang, Phoenix is the web framework layer.
- > specialized hosting
What do you mean?
My private next.js fullstack slop runs dockerized on my kubernetes cluster and for auth I use auth0, because I am too lazy to run keycloak or whatever dockerized auth slop is currently en vogue.
- It's possible but most default to vercel and it's required if you want the fancy stuff (hybrid). And you made my point, Kubernetes is overkill as well.
Regarding auth, in phoenix it's literally as simple as "mix phx.gen.auth Accounts User users" and boom, your users live right in your database for free.
- Years ago I used surface ui's colocated css to great effect. Super happy to have it incorporated into mainline live view
- What are the pros and cons compared to ASP.Net/Blazor?
- The BEAM virtual machine. Its has lightweight isolated processes, message passing, supervisors, hot-ish runtime introspection, and fault containment are not libraries bolted on later. They are the substrate. not an after thought.
if you are build an app that needs the following: + many concurrent users + real-time UI + background jobs + workflows + stateful sessions + distributed events + failure isolation + “this thing should keep running for months”
You're going to want the thing built on the BEAM.
- But it doesn't have neither AOT nor JIT.
- I believe BEAM bytecode is now JIT-ed.
EDIT: It is, since OTP 24 was released in 2021:
https://www.erlang.org/downloads/24
> The BeamAsm JIT-compiler has been added to Erlang/OTP and will give a significant performance boost for many applications. The JIT-compiler is enabled by default on most x86 64-bit platforms that have a C++ compiler that can compile C++17.
- Many people love liveview.
Many people dislike blazor and it has had its reputation sullied by Microsoft treating it as “new webforms” (yes, they do. It is literally the official migration path for legacy webforms projects).
The pro of blazor, arguably, is c# and the .Net ecosystem.
If I personally had to choose, I wouldn't choose blazor over almost any other technology because I’ve had bad experiences with it.
Technically, they're very similar, but the devexp matters, in my oppinion.
- TLDR; LiveView is web only.
There have been efforts to make LiveView native, but it’s extremely difficult to do so, and thus far (to my knowledge) all have failed.
I was thinking about this the other day because carsandbids (Doug DeMuro’s car auction site) uses Blazor (at least as far as I can tell). And I think that’s one of its biggest advantages of Blazor—- is that it is capable of producing native apps and web apps while LiveView is resolutely not. And that’s because Microsoft can pay for it (or at least sponsor huge amounts of supporting infrastructure).
And FWIW— that’s an extremely difficult problem to solve. It requires an enormous amount of funding, both a huge team capable of both understanding Android and iOS SDKs and capital to employ folks on pure engineering challenges (hence why MS or Meta can). End users don’t care if it’s made with LiveView, Blazor, React, Java, SwiftUI, et. al. And, the list of companies that can facilitate that long term is extremely small.
There’s also the issue of OTP being non-trivial to implement or meaningfully transpile into another language/runtime. Erlang, BEAM, and OTP were made together for each other in a very peculiar and specific way, for a specific set of problems, and if it wasn’t a necessity that they were developed together it would be a dead language, runtime, and platform (and for the record it’s absolutely not).
- Why not just build mobile apps in their native language (Swift etc)? Anyways, end users absolutely notice and care - cross platform mobile apps are all hot garbage without exception.
- Especially now that you can likely throw the mobile conversion to an LLM and judge the feasibility of it's maintenance once it's done.
- That’s what I would do that personally. I hate wrappers around native SDKs. But I also learned them.
A lot of folks assume mobile apps are “difficult” because of the underlying language. But it’s not the language that’s an issue, it’s the SDKs. They’re so wildly different from each other, and the way things work on the web, that it’s (IMHO) a losing proposition to do so.
That’s not to say things like Blazor or React Native don’t have a place but that place is one that’s inherently difficult to maintain without huge amounts of ongoing effort and capital invested in non user facing features.
- I am a fan of the idea, but the websocket is also quite a big attack surface; you can do a lot more by sending messages over this socket to your phoenix app than you would likely expect to have exposed via some api on another framework.
It’s difficult to secure, in my opinion. Perhaps not impossible but the cost of doing so pretty much eclipses the benefits of using liveview imo.
- You authenticate and authorize them the same way you do any other frontend requests. The socket gets an authenticated user and you handle messages in that scope. It’s not hard at all. Since messages have a shape that has to structurally match you can’t just dump arbitrary messages on the socket and get replies.
- I haven’t used it for anything in production so I haven’t seen these issues, could you give a bit more detail? I’m mostly wondering why you’d have any more websocket messages that you respond to than you would APIs if you were using any other approach. Does LiveView itself respond to certain messages bypassing your app?
- There is some propensity to forget that you're basically making a REST API because its all "in my process, responding to messages", it feels like you're writing your regular server side render controller. But really instead of `PUT /create/post` its `websocket.send("create_post", {})`, so you need to understand that if you only want to operate on `user_id=1`, you need to not just accept `{user_id: 1, ...data}`.
I dont think its inherently any more insecure than another method, you just have to recognize that clients can create malicious requests to `handle_event(my_event, params, socket)`, just like you might to `my_action(params, conn)`. It's also pretty painless, normal, to just crash on bad data, it will only effect that one naughty lv process.
You could also send "control" signals to the phoenix liveview process via the same socket but I dont think that actually as much surface outside of heartbeats and closing the socket.
- Why? It's the client that initiates the connection.
- I’m not sure how I feel about the CSS integration. Nor the collocated JS that was somewhat recently released.
On one hand, yes it is convenient, but on the other it could become a huge mess. It reminds me of Rails 2.x where it became almost impossible to debug, or fix front end code that used rjs or whatever it was called. Because disparate snippets of JS were littered throughout your code base in files that were hard to find.
I’m sure the Phoenix team has put a lot of effort into it, and I truly hope it slaps. I myself am just really hesitant to use it, when CSS files and non colocated JS work just fine. I’ll probably be waiting a couple years before giving it a try
- I quite like the colocated JS. I much prefer to define a components "hook" code inside the component. I think you could abuse it, I would never put colocated JS just in some template to include it "just to avoid writing a js file" but for keeping `email_validator.js` code right next to the `email_input` component, its quite nice I think.
The nature of them being basically forced to inherit the module name means its pretty obvious that `MyAppWeb.Admin.Components.EmailValidator` is in the `MyAppWeb.Admin.Components` module. I also think it probably strongly depends on how much JS you actually have, most of my liveview apps have it "here and there" to enhance something or minor DOM fiddling, if you are booting react components everywhere and have some other pile of existing js code, its probably not so good.
- Surface, vue, and svelte have all have colocated css and js for ages. It usually results in easier to maintain code, without having to resort to unsolutions like tailwind
Global styles can still be global, but component level styles stay at the component level
- To be honest that's copied from the JS frameworks. I tend to agree with you but sometimes scoped CSS is nice to have.
- [dead]
- [flagged]