FolderStructure.dev

Phoenix LiveView Project Structure

LiveView-centric architecture for real-time UIs. Rich interactivity without client-side JavaScript.

#phoenix #elixir #liveview #real-time #websocket
PNGPDF

Project Directory

my_app/
mix.exs
mix.lock
.formatter.exs
.gitignore
config/
config.exs
dev.exs
prod.exs
test.exs
runtime.exs
lib/
my_app/
Business logic
application.ex
repo.ex
accounts/
accounts.ex
user.ex
catalog/
Example domain context
catalog.ex
product.ex
my_app_web/
endpoint.ex
router.ex
telemetry.ex
live/
LiveView modules
product_live/
Feature-scoped LiveViews
index.ex
List view
show.ex
Detail view
form_component.ex
Reusable form
user_live/
settings.ex
profile.ex
components/
core_components.ex
Buttons, forms, modals
layouts.ex
layouts/
app.html.heex
root.html.heex
controllers/
Non-LiveView routes
page_controller.ex
page_html.ex
priv/
repo/
migrations/
seeds.exs
static/
assets/
js/
app.js
LiveView hooks
hooks/
JS interop
index.js
css/
tailwind.config.js
test/
test_helper.exs
my_app/
catalog_test.exs
my_app_web/
live/
product_live_test.exs
support/
conn_case.ex
data_case.ex

Why This Structure?

LiveView lets you build rich, real-time UIs entirely in Elixir. State lives on the server, changes push over WebSocket, and you write zero JavaScript for most features. The live/ directory organizes LiveViews by feature, each with its own folder for related views and components.

Key Directories

  • lib/my_app_web/live/-LiveView modules organized by feature
  • live/{feature}/form_component.ex-Reusable LiveComponents
  • assets/js/hooks/-JavaScript hooks for client-side interop
  • components/core_components.ex-Shared UI components

LiveView Example

defmodule MyAppWeb.ProductLive.Index do
  use MyAppWeb, :live_view

  def mount(_params, _session, socket) do
    {:ok, assign(socket, products: Catalog.list_products())}
  end

  def handle_event("delete", %{"id" => id}, socket) do
    Catalog.delete_product!(id)
    {:noreply, assign(socket, products: Catalog.list_products())}
  end
end

Getting Started

  1. mix phx.new my_app --live
  2. cd my_app && mix deps.get
  3. mix ecto.create
  4. mix phx.gen.live Catalog Product products name:string price:decimal
  5. mix phx.server

When To Use This

  • Interactive dashboards and admin panels
  • Real-time collaborative features
  • Forms with instant validation
  • Live search and filtering
  • Apps where you want to minimize JavaScript

Trade-offs

  • Server state-Each user connection holds state in memory
  • Latency sensitive-Round-trip to server for every interaction
  • JS still needed-Complex animations or offline require hooks

Best Practices

  • Use phx.gen.live to scaffold CRUD LiveViews
  • Extract shared UI into core_components.ex
  • Keep LiveView modules focused—one per page
  • Use assign_async/3 for expensive data fetches
  • Handle handle_params/3 for URL-driven state