Seeking Experiences with Phoenix, LiveView, and Elixir for Solo Developers and Small Teams

There is Livewire in Laravel too.

1 Like

I actually tried Livewire before I discovered LiveView, and the difference between the two is significant. Livewire felt much harder to integrate with other JavaScript libraries, whereas LiveView made that process a lot smoother.

Livewire also relies uses HTTP requests, and its rendering approach, re-rendering the entire component tree, felt inefficient. The overall experience was noticeably slower and clunkier & the server does not have a bidirectional line for communication with the client … you still need to setup the sockets yourself using Laravel Echo… PHP simply isn’t built for managing real-time connections like the BEAM (Erlang VM) is, the BEAM’s lightweight process model and concurrency capabilities are in a different league.

When I compared both side by side, building the same product with LiveView on the right and Livewire on the left, the difference in performance and developer experience was huge.

LiveView stands apart from Hotwire, HTMX, and Livewire thanks to its use of persistent WebSocket connections and the BEAM’s lightweight, highly concurrent runtime.

2 Likes

Building interfaces with these hacky template languages will never scale to real applications. There is a reason tools like React and its endless array of clones (including LiveView!) were created.

I am not directing this to you in particular (I see from your next paragraph that you actually understand what I mean here), but:

I have seen a lot of discourse in this direction, where people argue “you can just build modals/drawers/etc with a JS toggle, you don’t need React/LiveView/whatever”. The only reason you can get away with such a simple hack (toggling visibility of pre-rendered HTML) is because the use case is trivial. If you try to build applications with actual functionality you quickly realize it is never that simple.

For example, I have modals which are stateful, and can be minimized. It is possible to have multiple open at a time and switch between them. The UX there is similar to a windowed desktop system, or the drawer style dismissable window which has become a common replacement on mobile. (A careful reader will note this is not actually a modal in the historical sense, but the word has lost most of its meaning.)

It is not possible to implement this functionality with simple toggles because the modal actually needs to be allocated with state, which can then change.

Most “server rendered HTML” frameworks (in the HTMX style) cannot properly model functionality like this. React can of course, on the client, but note that (as Jose once wrote) applications often have server-side state as well. In my case, modals like “New Bookmark” actually perform server-side fetching when you paste in a link, to show a preview. The document is held on the server (in LiveView) to be put into a bookmark, since we may as well keep it instead of fetching it again on submit!

Take note of what has happened here: because the application is implemented on the server, it can do things the client cannot do like fetch an external webpage, parse it, and hold it for submission. Since those modals are stateful, there could be a few open at once! You can build real applications this way, with deep, interactive functionality. Because unlike most LiveView alternatives, LV is essentially React on the server.

There are entire classes of applications where almost all of the important state is server-side. Cloud consoles (think EC2) are a great example. LLM agents like “Deep Research” are another recent one. Anything “multiplayer” has a lot of server-side state which could be easier to deal with on the server than the client, depending on the app you’re building.

As a counter-example, an app like Figma has plenty of server-side state (multiplayer) but you would be insane to try to build such a thing with LiveView. The client state still wins, in that case.

3 Likes

I totally agree, some apps are best built with a JS framework, and some even need WASM. But for solo devs, indies, or small teams, is it really worth the added complexity? Or does it just slow things down? I mean, I’m a solo dev, I’m not building Figma or porting an entire Office suite to the web, lmao.

In my experience, around 80% of web apps are mostly server-driven, and only a small subset truly needs heavy client-side interactivity. This is especially true for smaller teams that can’t afford to pour tons of resources into complex UX when business logic should be the priority.
“Seeking Experiences with Phoenix, LiveView, and Elixir for Solo Developers and Small Teams
And the thing is… working in 2 codebases is a nightmare, with js frameworks your hand is forced to use these meta frameworks like next or nuxt or sveltkit and buy into serverless / everything is a service everything is a library paradigms otherwise you aren’t really taking full advantage of the ecosystem & E to E typesafety etc …
The complexity & slowdown VS benefits… here the thing, if i am going to launch products most of them are going to fail, we talk about 2 different scenarios, 1/20 things i make are going to not be profitable … i cannot afford to care about having stateful modals and such things …
let me put it in different words, i have 20 roads ahead of me, i don’t know which one will lead me to the destination, i can go and choose to assemble my car from scratch, drive there, and discover it ain’t the right path, and start over assembling a whole new car from scratch, drive the next path, discover it ain’t the right one, and rebuild the entire car from scratch again
or… just grab a car that has everything pre assembled, and boom let’s go drive drive drive until i find the right path
You get my point ? Having a stateful modal isn’t going to determine if my product is going to sell, the business logic is what determines that, these things come AFTER you make $… than you take feedback & iterate & improve the UX where it matters most, not before you even figure out if you are profitable or not, maybe what you think could be better UX doesn’t even matter for the customers, if you put too much time into these things before even having customers paying you, than you have basically over engineered a dead product gg well played…
you know… there’s a meme about the devs never being able to ship anything because they always hyper focus on the technical details while the business people don’t give a flying fck about that stuff and just care about the numbers
i can’t even scaffold a basic auth and crud with validation in these meta frameworks, the most repetitive tasks ever, i need to download a bunch of fragmented libraries and stick them together, there is no one way of doing stuff, so each time you reinvent the entire universe and it’s such a waste of time
Once you are put in a situation where you have only about 5% chance of getting paid, the priorities shift (maybe i am exaggerating but you get my point …)

5 Likes

Also, just a quick note, sorry if I come across as rude at any point, that’s definitely not my intention. English is my third language, and sometimes it’s a bit hard to express things exactly the way I mean them. I really appreciate all your input, your opinions mean a lot and are genuinely valuable to me.

2 Likes

i mean there are ppl selling boilerplates for these frameworks :joy: that’s the ultimate proof that there’s something wrong because that should just be the framework https://shipfa.st/

again react cannot even do routing on it’s own, spa’s are horrible for seo so your hands are forced to use these meta frameworks or something like inertiajs if you want ssr & routing …

The JavaScript ecosystem often encourages the creation of overly complex tools designed primarily to sell you a range of services and cloud solutions. Ideally, your framework should handle these tasks seamlessly for you. You shouldn’t have to hunt down an ORM created by a startup that uses it as a lead magnet to push you toward their other paid offerings. In many cases, the entire framework itself becomes a lead magnet to lock you into a specific platform.
Supabase shouldn’t exist … Phoenix does what supabase does out of the box, more, and better, and you actually own it, you may argue supabase uses open source technologies and it can be self hosted, that’s where they get you, that’s a facade, that’s the magnet they use to get you hooked, the moment you try to self host the thing you realize that by doing that you are getting a subpart version of the thing…
The ecosystem itself is pro complexity for profit

1 Like

$25/ month => Concurrent Peak Connections
500 included
then $10 per 1000

this is a fcking joke…
react svelt vue don’t exist in a vacuum usually if you use them you must use something that is end to end type safe or at least that has ssr and routing, so probably next nust react router v7 or sveltkit and that automatically means you must use vercel or some other serverless thing and at that point might as well build everything in nextjs

Credentials:

  • 10+ YOE
  • “Staff+” Engineer (whatever that means nowadays)
  • Worked in both massive corporations, medium sized companies, small startups, startups where I am the only person in Engineering (“Founding” engineer seems to be the fitting title here).

Your experiences using this stack in small teams or solo projects.

At my current role I am the “founding” engineer. I am alone in engineering and I basically call all the technical shots.

After spending sometime with what I was given initially (a platform built by contractors), I decided to do a rewrite of the app (keeping the domain and the database, of course). The reasoning for this “cardinal sin” is long and not part of this topic. I choose Elixir with Phoenix as it is an IOT domain and what we are doing fits perfectly with these tools. This is also the first time I am running this in production.

So far the development has been a breeze. My background is in the JS world (“Full stack”) and while I understand any tool can be misused, navigating both languages and ecosystems I can see the massive contrast between both.

In JS land, everything seems overengineered. Everything gets updated frequently for a myriad of reasons and API breakage is not uncommon (and sometimes without much benefit). The build systems are a bit more sane now but still messy (my first interaction with the ecosystem was Webpack. Go figure.). React is the chosen primary tool for development and it has been engineered in such a way that now NextJS is the “recommended way” of using it. And this is just the UI part. There is the NodeJS overengineered bespoken architectures. I won’t expand further as what I have shared is probably repeated ad nauseam across the internet.

In Elixir, dependencies move slower and sometimes you are even encouraged to build your own solution as the language gives itself for doing that. It is a joyful experience. Phoenix as a framework is mature and LiveView has been properly design to cover many use cases. I don’t have to design an API (specially the effort that goes around designing a “proper” API with its long term consequences), jump to another project, adjust how to handle the response or wait for some autogenerated artifact and act on that. And then rebuild everything in both systems.

How it has impacted your productivity and development workflow.

I do not have exact metrics of my productivity other than my own gut feeling and experience. I feel I am more productive in general. Since I am still new to the tool I can’t say I am leaps and bounds beyond what I would be doing if I had to use NextJS, however I can tell that once I get to a similar maturity I would be flying.

Any challenges you’ve faced and how you addressed them.

A few.

  • You can’t just throw things to the heap and reference them. To keep state you need to deal with genservers.
  • Ecto is the best data wrapper I have used, but it can be a little abstract using the raw query syntax. I learned to love piping statements to mitigate this. ( query |> where([blah], blah.id == 1) )
  • If you love to just go to your favorite UI framework website and do npm install the-framework-react you will have a bad time (assuming you’re using LiveView here). Given that Tailwind is pre installed and preconfigured, just grabbing tailwindcss library/ui kits and adapting them to heex did the job. Easier than expected.
  • It takes a bit to get used to the new keywords def, do, end
  • You might be tempted to treat modules as classes. They’re not.
  • I’ve had a few problems with structs and maps. Maps are raw to the definition of a map, Structs are a maps, but more strict and have some additional properties.
  • On the map/struct topic, accessing a property value. I’ve been burned over using var[“key”] instead of var[:key].
  • I do not like the syntax of how functions are passed around but there is not much I can do here. random_function(&App.ModuleName.this_function/2)
  • Alias, import, require, use. Very clunky.

Comparisons to other stacks you’ve used in terms of simplicity and efficiency.

Batteries are fully included here. What I like about Phoenix is that it is explicit for being a framework. The efficiency in the DX department is great (assuming you’re using LV). ESBuild is preconfigured, Tailwind is preconfigured, both are “integrated” with the Elixir side. On efficiency, the BEAM VM is a specialized tool that was created with trade offs in mind (nothing is free) and for web development it is a perfect match. What I like the most is that one user stumbling upon a potentially catastrophic bug won’t crash the system for the other users unlike other languages (unless, of course, you’re messing with the data store – that’s a guaranteed degraded experience for everyone. :clown_face:).

How it compares to other frameworks like rails laravel & django

I haven’t used Laravel. I used Rails a while ago and I am migrating the system off Django. I can’t speak for Node has every project I have dealt with has its own custom architecture.

I do not like Django, but I can see why other people with different mindsets might like it. To me it opens the doors to OOP hell with a lot of inheritance, abstraction and misdirection. I also happen to dislike Python in the context of large size applications. I have stated my bias.

Phoenix as it is now does a lot of the things Django offers out of the box. One thing that is nice for Django for some projects is the default admin. Phoenix has a few but you have to integrate them. That is the only big “loss” I have experienced. Otherwise, I don’t feel I am missing anything that Django offered. I am way happier now.

And I am running a 1 man show.

7 Likes

Thanks a lot for the input :heart: :heart: :heart: :heart: :heart: :heart:

For learning purposes, it can be put simpler in that a struct is just a map with a :__struct__ key that references a module. You can play around with this for proof:

iex(1)> defmodule Foo, do: (defstruct [:bar])
{:module, Foo,
 <<70, 79, 82, 49, 0, 0, 8, 184, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 246,
   0, 0, 0, 22, 10, 69, 108, 105, 120, 105, 114, 46, 70, 111, 111, 8, 95, 95,
   105, 110, 102, 111, 95, 95, 10, 97, 116, ...>>, %Foo{bar: nil}}
iex(2)> foo = %Foo{}
%Foo{bar: nil}
iex(3)> is_struct(foo)
true
iex(4)> foo = Map.delete(foo, :__struct__)
%{bar: nil}
iex(5)> is_struct(foo)
false
iex(6)> foo = Map.put(foo, :__struct__, Foo)
%Foo{bar: nil}
iex(7)> is_struct(foo)
true

Based on your generally really apt breakdown of how you understand Elixir, I feel you can learn to love this one easily. I’m sure you’re aware that arity is part of elixir function signatures—so foo(1) is actually a completely unrelated function to foo() according to the compiler, which is important for pattern matching. So there is no way that passing function references by name alone is possible.

In name yes(maybe), in practice no, but that’s a whole other convo.

2 Likes

Oh ya, also for learning purposes, if you are using dbg or IO.inspect, they are optimized for debugging, but not for learning. If you really want to see what a struct looks like, you can pass structs: false as an option to either of them, eg: dbg(%Foo{}, structs: false) which will bypass inspect protocol and show you everything as a map.

That’s what I meant to convey. A level of interactivity has been lost in the transition from desktop apps to web apps. The conversion of persistent, user-specific UI state to transient client-side state is one of those losses. LiveView gives tools to take action on this balance.

Re : figma, I build multiplayer live document editors where people can generate, drag, add, delete stuff on pages, on top of either Vue+Channels or Liveview+JS Hooks recently. I don’t use CRDTs or advanced reconciliation mechanisms because they often generate technically correct but user-obtuse merges.

My take on that is that cooperation and reconciliation are business problems. By talking to my users we quickly found out that in their case, object-level per-user locking + an override mechanism was the best choice. Offline was also not necessary since they need to be online to have access to the company servers/resources that are used in those documents.

There’s no reason that Bob would edit the object that Sandy is currently working on. So he sees an object-level lock that says “Sandy was working on that object 45s ago”. But maybe she left her desk and Bob needs an edit right now to send the document. To that end, there’s an “override and take lock” button that allows Bob to take control.

So my client state is transient per edit and the server always holds a global truth. But I wouldn’t do a figma with LiveView because the coop and multiplayer rules are different.

There’s no reason to shoehorn Liveview on everything, but it can be used for quite interactive solutions too if the rules of the game are sensible.

4 Likes

I think that even in situations that are not predictable and requirements change in the way that liveview no longer makes sense, picking liveview for the initial phase is still a great idea, as you have that huge boost of productivity in the exploratory phase.

Usually if you are just starting out on a technology that is entirely new, the chance that you will need to rewrite and rethink the architecture from the ground is very high. You can easily asses at that point if going with a 2 stack variant makes more sense.

3 Likes

If you go back through my message you’ll notice that it was not actually about server vs. client rendering, but about hacky “template” approaches vs declarative React-style rendering. LiveView and React are equivalent in this respect, and they stand opposed to HTMX-style libraries on the server and JQuery-style libraries on the client. Though note that, unlike on the server, the imperative style is practically extinct client-side as React has so thoroughly won and JQuery is effectively dead (these are good things).

But to answer your question, in my opinion: yes declarative rendering (React) is absolutely worth it. I disagree that it is added complexity. React is not very complicated. It is essentially the simplest thing you can create to do the job; if you don’t have React, you will either slowly rebuild it (badly) from scratch or you will simply be unable to build good interfaces at all.

You are not forced into anything, you are making a choice. Try this: paste a 3kb vendored copy of Preact+hooks into a codebase and absolutely nothing else, and then build an application with that. You will find that it’s much easier to build applications this way than to hack things together with vanilla JS DOM operations and so on. These tools were created for a reason, and not everything in this world is hype.

Yes of course if you pull in the latest diseased NPM framework du jour with 3000 dependencies you are going to suffer. I promise you no matter how much you hate that stuff, I hate it more. I started writing Elixir just to escape that nightmare, and I will never go back. But that doesn’t mean React, as a paradigm, is bad. The JS ecosystem just happens to be a complete and utter disaster.

You cannot afford such things because you are using bad tools which are not capable of expressing them. The question you should be asking is “what tools and abstractions make building such things easy”.

I disagree with this mentality, and I think it’s a big part of why software has become so awful to use. I hope we can move past this, as an industry. Not everything in this world is, or needs to be, a B2B enterprise SaaS. I miss good software.

3 Likes

What is your setup when it comes to API contracts with 2 stacks? I can see how using for example ash+graphql might be pretty productive and painless to use, but I detest having to manually maintain those contracts. This is one of the big reasons I will take clunky UI any-day instead of spending a huge amount of time on maintaining those contracts. Ideally if there would be a technology that would integrate automatically the contracts, like for example I think there was sveltekit+houdini, I might consider giving a try to this for my future projects.

Also, it would be great if you could motivate why react and not for example svelte, vue or yet another frontend framework? It’s OK if that is the main reason is that it is the most efficient and comfortable technology for you personally, but please do mention.

3 Likes

I am referring to React in these comments as a paradigm, not as a library. I have no experience with Svelte or Vuejs but my understanding is that they both at least partially inherit the reactive paradigms React popularized in the frontend world, though in their own ways. I am skeptical of the new generation of “signal-based” reactive libraries like SolidJS, but I don’t have hard opinions yet. Svelte is ironically headed down this path because it turns out that doing everything at compile time is a bad idea (who would’ve thought, Itanium had such a bright future…), but anyway it’s all the same stuff at the end of the day.

Importantly, the point I’m trying to make here is that LiveView is one of those libraries, like React and its derivatives. It’s nothing like HTMX/LiveWire/HotWire and so on.

Oh boy am I ever the wrong person to answer this question lol. I am all in on LiveView for now, but I am writing this comment as I start the first pass of the recovery algorithm for my bespoke distributed database because I want to get rid of Postgres. I hate dependencies, and what I want more than anything is my own stack. The Elixir ecosystem is the only thing I can even tolerate at this point.

My medium-term plan is to write my own JS library (a simple React clone) from scratch and use that when LiveView is not enough. LiveView is enough for most things, but my standards are really high. Still in the research phase on this one, months away from even starting. My first product(s) will ship in pure LiveView/Postgres, very soon now… :slight_smile:

2 Likes

We are speaking in abstractions, which is always dangerous territory for misunderstandings. With that said…

I think what we all really want, certainly what I want, is some sort of framework where those contracts no longer exist. Generating contracts, APIs, and abstractions is paving the cow paths from which we are all suffering. There is a way out here, but the problem is extremely difficult to solve.

There are technologies which have come very close before being stamped out. MeteorJS, Firebase… those guys almost had it. But it just never quite happened.

LiveView, actually, makes some good progress here. By coupling the rendering directly to the backend it becomes a bit easier to avoid death by a thousand REST calls, and so on. It doesn’t actually solve the problem, but it makes designing systems that way (badly, that is) less tempting. Progress.

The problem at the end of the day is idiomatic LiveView is strongly coupled to Ecto (an excellent library btw), which is in turn inescapably coupled to the common SQL RDBMS architecture. Unfortunately this architecture is poison for good applications. The fact that Meteor/Firebase had to throw those things away first, to the degree that they are remembered as databases more than anything, is a good hint as to where the real demons lie.

I will note for the record that I don’t think the relational model is the enemy - if used right it’s one of the greatest inventions in the history of computer science. It’s just that these SQL RDBMS that we have are not using it right, because they are not designed for building applications. They are designed for conducting censuses and managing supply chains.

I dream of solving these problems (and so should you, whoever is reading this), but they are some of the hardest problems ever to exist in our field. I am hoping at least for some incremental progress, and perhaps a short, sweet reprieve from the suffering. Or something.

2 Likes

I’m intrigued. Would you mind elaborating and enlightening me? :slightly_smiling_face: