Implementing Phoenix LiveView: From Concept to Production
- Phuong Van
- 24th Oct 2024
- 9 min of reading time
When I began working with Phoenix LiveView, the project evolved from a simple backend service into a powerful, UI-driven customer service tool. A basic Phoenix app for storing user data quickly became a core part of our client’s workflow.
In this post, I’ll take you through a project that grew from its original purpose- from a service for storing and serving user data to a LiveView-powered application that is now a key tool in the client’s organisation for customer service.
Our initial goal was to migrate user data from an external, paid service to a new in-house solution, developed collaboratively by Erlang Solutions (ESL) and the client’s teams.
With millions of users, we needed a simple way to verify migrated data without manually connecting to the container and querying the database every time.
Since the in-house service was a Phoenix application that uses Ecto and Postgres, adding LiveView was the most natural fit.
After we had established the goal, the next step was to create a database service to store and serve user information to other services, as well as to migrate all existing user data from an external service to the new one.
We chose Phoenix with Ecto and Postgres, as the old database was already connected to a Phoenix application, and the client’s team was well-versed in Elixir and BEAM.
The ESL and client teams’ strategy began by slowly copying user data from the old service to the new database whenever users logged in. For certain users (e.g., developers), we logged them in and pulled user information only from the new system. We defined a new login session struct (Elixir struct), which we used for pattern matching to determine whether to use the old or new system. The old system was treated as a fallback and the source of truth for user data.
With this strategy, we could develop and test the new database system in parallel with the old one in production, without affecting regular users, and ensured that everything worked as expected.
At the end, we performed a data dump for all users, configuring the service to use the new system as the main source of truth. Since we had tested with a small number of users beforehand, the transition was smooth, and users had no idea anything had changed from their end. Response times were cut in half compared to the previous solution!
The addition of LiveView to the application was first thought of when the ESL team together with the client team wanted to check the test migration data. The team wanted to be able to cross reference immediately if the user data has been inserted or updated as intended in our new service. It was complicated and cumbersome at first as we had to connect to the application remotely and do a manual query or call an internal function from a remote Elixir shell.
Initially, LiveView was developed solely for the team. We started with a simple table listing users, then added search functionality for IDs or emails, followed by pagination as the test data grew. With the simple UI using LiveView in place, we started with the data migration process and the UI helped tremendously when we went to verify if the data got migrated correctly, and how many users we have successfully migrated.
As we demonstrated the UI to stakeholders, it quickly became the go-to tool for customer service, with new features continuously added based on feedback. The development team received many requests from customer service and other managers in the client’s organisation. We fulfilled these requests with features such as searching users by a combination of fields, helping change users’ email addresses, and checking user activity (e.g., when a user’s email was changed or if users suspected they had been hacked).
Later, we connected the LiveView application to sync and display data from another internal service, which contained information about users’ access to the client’s product. The customer service team was able to get a more complete view of the user and could use the same tool to grant or sync user access without switching to other systems.
The best aspect of using Phoenix LiveView is that the development team also owned the UI. We determined the data structure, knew what needed to be there, and designed the LiveView page ourselves. This removed the need to rely on another team, and we could reflect changes swiftly in the web views without having to coordinate with external teams.
There were some glitches along the way, and when we asked for feedback from the customer service team, we found several UX aspects that could be improved. For example, data didn’t always update immediately, or buttons occasionally failed to work properly. However, these issues also indicated that the Phoenix LiveView application was used heavily by the team, emphasising the need for improvements to support better workflows.
While our LiveView implementation worked well, it wasn’t without imperfections. Most of our development team lacked extensive web development experience, so there were several aspects we either overlooked or didn’t fully consider. Some team members had limited knowledge of web technologies like Tailwind and CSS/HTML, which helped guide us, but we realised that for a more polished user experience (UX) and smoother interface, basic HTML/CSS skills alone wouldn’t be sufficient to create an optimal LiveView application.
Another challenge was infrastructure. Since our service was read-heavy, we used AWS RDS reader instances to maximise performance, but this led to occasional replication delays. These delays could cause mismatches when customer service updated data and LiveView reloaded the page before the updates had replicated to the reader instances. We had to carefully consider when it was appropriate to use the reader instances and adjust our approach accordingly.
Mob programming way of working was also one of the factors that led to the success of this project. Our team consists of members with different expertise. By working together, we can discuss and share our experiences while programming together, instead of having to explain later in code review or knowledge sharing what each of us has implemented and why. For example, we guided a member who had more experience in Erlang/OTP through creating a form with Liveview, which needed more experience in Ecto and Phoenix. That member could then explain and guide others with OTP-related implementation in our services.
Mob programming helped our team focus on one large task at a time. This collaborative approach ensured a consistent codebase with unified conventions, leading to efficient feature implementation.
What began as a simple backend project with Phoenix and Ecto evolved into a key tool for customer service, driven by the power of Phoenix LiveView. The Admin page, initially unplanned, became an integral part of the client’s workflow, proving the vast potential of LiveView and Elixir.
Though we encountered challenges, LiveView’s real-time interactivity, seamless integration, and developer control over both the backend and UI were invaluable. We believe we’ve only scratched the surface of what developers can achieve with LiveView.
Want to learn more about LiveView? Check out this article. If you’re exploring Phoenix LiveView for your project, feel free to reach out—we’d love to share our experience and help you unlock its full potential.
Meet Erik Schön, Managing Director and and Nordics Business Unit Lead at Erlang Solutions. He shares his 2025 highlights and festive traditions.
Attila Sragli explores the BEAM VM's inner workings, comparing them to the JVM to highlight their importance.
Pawel Chrząszcz introduces MongooseIM 6.3.0 with Prometheus monitoring and CockroachDB support for greater scalability and flexibility.