When should I use a LiveView or a regular Controller?

Hello everyone,

I was using the normal controllers until I discovered PhoenixLiveView. Now I always use LiveViews and never the regular controllers… So I wonder when I should use a LiveView and when I should use a regular controller?

My feeling today is that whenever I would like to have interactions with the user, I should use a LiveView. What about normal controllers with GET/POST/DELETE/PUT actions?

For example, on my landing page I would like to add a simple cost calculator. This seems to be a good case for a LiveComponent. But a LiveComponent needs a LiveView, does that mean that my page has to be a LiveView?

I think it’s better if I always use a LiveView. What am I missing? What don’t I understand?

Thank you!


When serving html pages with LiveView, you use a “LiveView” instead of a controller to handle the interactions with the user. So it possible for a web application to only use LiveViews without the need of a controller, there is nothing wrong with this. Depending on the website, you may not need to use HTTP requests with verbs GET/POST/DELETE/PUT.

But LiveView is only used for html pages, which is not the case of the routes you define for GET/POST/DELETE/PUT. These routes may be used from an HTML page but they don’t need an HTML page to work.
For example, if you are creating an API, you still will need to use the verbs and handle the requests in a controller.

LiveView is only an alternative to serving HTML pages. You will still need Phoenix routes for other use cases.


You cannot manipulate the session from a LiveView (for example: using put_session for session based authentication).
The latest update added phx-trigger-action which lets you submit to a controller based route as a final action which makes it even easier to mix both ways.


Thank you both very much. This clarifies the use of LiveView for me.

Can you expand more on this? What do you mean…? Why can’t you?

I’m trying to think of the cases where I wouldn’t want to use LiveView. :slight_smile:

LiveView runs on top of Phoenix Sockets. Sockets run separately from the Plug pipeline and don’t have access to sessions but LiveView still provides a way to access them (once).

A LiveView is rendered twice, first when the static HTML is sent to the browser, and again when the browser establishes a websocket connection. The first render goes through the Plug pipeline and has access to the session data. This session data is signed and included in the HTML response. When this page is loaded in the browser, the signed session data is sent back to the server as a connection parameter to establish the LiveView websocket connection. After the first connection, there’s no way to change the contents of the session data as it is stored in the HTML itself.

I have been using LiveView since the first public release and the only time I have needed to think about this is to implement log-in and log-out. I now use a LiveView for everything, even the log-in page. I submit to the create controller action using the aforementioned phx-trigger-action that assigns the user to the session and similarly redirect to the delete controller action to log-out by clearing the session.

P.S. If this is how you are implementing log-in/log-out, make sure to also disconnect all active instances of LiveViews for the user.


I’m using the same strategy - my login page is a live view with a phx-trigger-action={@submit} for the final full page post to a (separate) LoginController which resets the session cookie… I was wondering if you were concerned with the fact that the form becomes “live” again for a brief moment (depending on latency) between the final live view event handler (that sets the phx-trigger-action) and the subsequent client side full page POST?

I’ve been looking for a way to have a live view event handler suppress the phx:page-loading-stop event (and the associated re-enabling form behavior) but no luck so far.

It would be nice if the form itself stayed “disabled” (all the inputs readonly) completely through the full page POST, but I haven’t found a way yet.