Phoenix + LiveView
Connected products, live updates and background work in one application.
Phoenix · LiveView · Ecto · PostgreSQL
Complete guide (Markdown) · Structured record (JSON)
Original source review: 2026-10-10. Core guidance rechecked: 2026-10-13. Check scope. Dependency combinations and setup need project-specific qualification.
Use cases
- Connected browser products and portals
- Real-time collaboration interfaces
- JSON APIs for native clients
- Durable application background work
Choose it when
- Server-owned state and business rules dominate a connected product.
- Phoenix conventions and OTP process lifecycles match the service requirements.
- A relational store can also support durable background jobs.
Consider another path when
- The main deliverable is a platform-native mobile UI or offline-first client.
- The application depends on a library, accelerator or vendor SDK unsupported by the intended Elixir deployment.
- A small static site, simple script or CLI does not need a running web application.
Working practices
- Keep business operations in contexts shared by controllers, LiveViews and workers. Contexts are not automatically processes.
- Enforce authorization on every protected operation, including direct context calls and after access is revoked.
- Use ordinary functions first. Add processes for state ownership or lifecycle; add durable storage for work that must survive a restart.
- Give retried external effects stable idempotency keys. Exercise reconnects, failed jobs and cross-account access.
Tools by job
Web application: Phoenix + its generated HTTP/asset defaults
Coherent routing, contexts and generated application structure.
Phoenix is unnecessary for a CLI or a service without HTTP; preserve existing architecture.
Dependency documentation and agent guidance: usage_rules for selected dependency guidance
Discover dependency documentation and synchronize selected upstream usage rules for agents
Development-only tool; inspect installed-version options and review generated content. Preserve Phoenix-generated guidance by default. An explicit README-only repository may configure file: "docs/dependency-rules.md" in mix.exs and link it from README; this destination is an optional project convention, not an upstream default.
Browser UI: LiveView + HEEx components
Shared server-side business operations and interactive screens suit connected forms, portals and collaboration.
Offline-first state, high-frequency local interactions and rich canvas editors can justify a dedicated client. LiveView does not remove HTML/CSS or all JavaScript.
Shared relational persistence: Ecto + PostgreSQL
Explicit queries, changesets and database transactions fit shared application data.
Changeset validation is not a replacement for database constraints or authorization; database operations and migrations need operational ownership. Current Ecto documentation deprecates Repo.transaction/2 in favor of Repo.transact/2. Follow the installed-version API and callback/result semantics; do not mechanically rename an existing transaction without tests.
Accounts and access control: phx.gen.auth + scoped context authorization
Generated first-party authentication keeps application-owned code; contexts authorize operations.
Check permission both on mount/navigation and each operation. Test revoked access and reconnect behavior; magic-link delivery needs a configured mail provider.
Durable background work: Oban with the existing Ecto/PostgreSQL database
Persist jobs and enqueue alongside domain changes in one transaction.
Task is only for explicitly disposable work and does not satisfy crash-durable delivery. Oban engine support and guarantees must be checked against the selected version; Redis is not a shipped Oban persistence engine. Oban Pro is an optional licensed extension, not a replacement for persistence.
Behavior and persistence tests: ExUnit + Ecto SQL Sandbox + LiveViewTest
Test contexts, data invariants, denied access and server-side UI behavior.
LiveViewTest does not establish browser JavaScript, accessibility or visual correctness. Inline/manual job tests are not a production recovery simulation.
Real-browser checks: PhoenixTest.Playwright for critical browser flows
Exercise hooks, navigation, reconnects and actual browser behavior omitted by server-side tests.
Adds Node/package-manager/browser binaries and sandbox configuration; verify supported wrapper features. It is an editorial extension, not a Phoenix generator default.
Code quality: Mix formatter and compiler warnings; Credo when selected
Fast local feedback plus consistency checks; select checks appropriate to project size.
Static analysis does not prove domain correctness. Dialyxir adds analysis/PLT maintenance and is not a mandatory starter dependency.
Security checks: Hex audit + Sobelow, alongside permission tests
Hex reports retired packages and known advisories; Sobelow finds common risky code patterns.
Use the installed Hex version’s behavior. Scan findings need review; configure a non-zero Sobelow exit threshold and do not blanket-suppress findings. Neither proves the application secure.
Deployment: Mix release + runtime configuration
Package application and runtime with explicit migration/server entry points.
Build for the target OS/architecture and native libraries. Host choice, secrets, migrations, TLS, backups, restore and rollback remain separate responsibilities.
Native mobile client boundary: Platform-native clients consuming Phoenix APIs
Preserve native UI/platform ownership while sharing server-side domain operations.
Do not advertise Elixir as a complete native mobile default: LiveView Native’s inspected README uses release-candidate dependencies and platform-specific clients. Validate target support, offline behavior, accessibility and signing independently.
Project instructions: README navigation + generated Phoenix agent guidance
Keep generated stack conventions available to coding agents
Preserve maintained repository rules; --no-agents-md is an optional project choice, not the Phoenix default.
Transactional email: Swoosh + selected provider adapter
Mailer adapters and test delivery fit generated Phoenix account flows
Configure adapter/client dependencies and sender credentials; keep test/local adapters in development only. Use Oban for required queued delivery; a Task has no durable retry guarantee.
Uploads: LiveView uploads
Built-in upload configuration and consumption fit connected forms
Configure allow_upload limits and authorize attachment association; persist consumed files before temp cleanup. External storage integration and content validation remain application work.
Realtime application events: Phoenix.PubSub
Local/distributed publication updates connected views and channels
Supervise PubSub and subscribe to scoped topics; authorize each subscription/action and test reconnect. PubSub is transient broadcast, not durable replay or a message queue.
Build with the stack’s strengths
Architecture and developer workflow.
Phoenix web modules call application contexts; Ecto supplies persistence boundaries. LiveView maintains connected server-side interaction, while Channels expose a client-facing realtime protocol. Recommendation: model domain operations through contexts and supervised responsibilities rather than translating every old controller, global singleton or database serialization bottleneck literally.
Version scope: Fetched documentation: Phoenix 1.8.15, LiveView 1.2.12, PubSub 2.4.1, Plug 1.20.3, Ecto 3.14.2 / Ecto SQL 3.14.0, Oban 2.24.1, Exq 0.25.0 and OTP 29.1.1 ETS. Installed dependency compatibility is unqualified; pin the actual application before using version-specific APIs. · Reviewed 2026-10-11
Architecture boundaries
- Recommendation: contexts own business operations, Ecto Repo owns database access and explicit transactions join related writes. A single GenServer around all queries is an application choice, not a Phoenix requirement.
- Phoenix PubSub has a distributed-Elixir adapter and a Redis adapter. Redis can remain appropriate when deployment or interoperability requires it. Recommendation: identify the required delivery boundary before selecting the topology.
- Oban requires an Ecto-backed supported SQL engine. Its installation documents PostgreSQL, SQLite and MySQL; selecting PostgreSQL is this catalogue's target composition, not a universal Oban prerequisite. Recommendation: preserve durable external effects through idempotency and recovery checks.
Tools and feedback
- For a disposable target, mix phx.new PATH generates a Phoenix application with selectable database and HTML/LiveView options. In an existing project, inspect mix.lock, generated modules and maintained conventions before regenerating anything.
- When manually installing the selected Oban version, adapt mix ecto.gen.migration add_oban_jobs_table and mix ecto.migrate from its installation guide; configure the engine, Repo and supervised Oban child. Do not copy PostgreSQL settings into a SQLite or MySQL target.
- Use mix test for application tests and the generated Phoenix connection/channel fixtures. Recommendation: add mixed-version payload, authorization and restart scenarios; a passing formatter or compiler does not establish those contracts.
- For a release build, adapt MIX_ENV=prod mix assets.deploy and mix release from the Phoenix deployment workflow; runtime.exs owns runtime configuration. Recommendation: verify database migrations, job supervision and cluster/PubSub connectivity separately from HTTP startup.
Translations to avoid
- Avoid replacing a durable queue with spawned tasks or an in-memory notification list while calling the change equivalent. Recommendation: explicitly accept the changed crash and retry behavior or retain a persistent queue.
- Avoid treating Exq's Resque/Sidekiq-compatible transport format as proof that Ruby Active Job wrappers, classes and serializers execute in Elixir. The exact consumer and payload contract still needs qualification.
- Avoid assuming Plug cookies decode Rails cookies: Plug exposes its own serializer, salts and cryptographic options. Avoid relying only on HTTP plugs for LiveView authorization; mount and events require checks.
- Avoid using ETS as a shared session or global lock store. Tables are local to their node and normally disappear with their owner unless an heir takes ownership. Recommendation: reserve ETS for explicitly reconstructible local state.
For an existing application
Keep the contracts while you change the stack.
These are documented options and proposed checks. Inspect the actual source application before adopting a transition.
Data and schema
Inspect the source
Inventory schema, constraints, record identifiers and callbacks previously triggered by writes. Ecto schemas and changesets must preserve the intended domain semantics, not simply the old table shapes.
During coexistence
Recommendation: keep the source application as the authoritative writer while Phoenix contexts read fixtures; move a tenant or domain operation with one named writer. Use additive schema changes and a single migration runner during shared-table operation.
Target design
Contexts calling Ecto Repo with explicit validation and transaction boundaries. Ecto.Multi composes related Repo operations in one database transaction; cross-store side effects require a separate delivery design.
Rollback
Recommendation: return the domain writer to the source while preserving additive schema and reconciling accepted new writes; delay destructive contractions until the rollback window closes.
Benefits and prerequisites
Recommendation: a context boundary can expose one reusable domain operation to LiveView, controllers and workers.
Requires: Resource authorization, constraints and side effects moved with that operation.
Tradeoffs: Shared-schema coexistence limits schema changes; external effects do not become part of a database transaction.
Checks before transfer
- Write a fixture through each allowed writer and read it from both runtimes; compare IDs, enum/null values, timestamps and constraint failures.
- Fail the second operation in an Ecto.Multi and verify the first database operation is absent; prove old readers still accept successful new writes.
Jobs and schedules: Retain Ruby workers behind an interface
Inspect the source
Rails workers currently own Ruby job execution, including Active Job/GlobalID serializers and backend retry/scheduling behavior. Record the actual Redis-backed backend and every backlog state rather than inferring it from the word Rails.
During coexistence
Recommendation, retain/wrap path: keep Ruby workers and their broker; expose a narrow producer endpoint or durable outbox relay for Phoenix. Ruby remains the only consumer and scheduler for retained categories, and the interface names payload version, business idempotency key and enqueue acknowledgement.
Target design
Phoenix web/domain code with retained Ruby worker ownership is a valid permanent composition when queue interoperability or Ruby libraries remain necessary.
Rollback
Recommendation: restore the old web producer while retaining the same workers; reconcile accepted interface/outbox entries before disabling the relay.
Benefits and prerequisites
Recommendation: the web layer can transfer before job execution without transforming the old backlog.
Requires: Defined producer interface, monitored delivery and retained worker deployment.
Tradeoffs: Two runtimes and the broker remain operated; domain write plus broker enqueue is not a shared SQL transaction.
Checks before transfer
- Submit a captured serializer/GlobalID case through the interface and confirm the intended Ruby class executes with its normal failure policy.
- Interrupt delivery after domain commit; recover it without duplicating a business effect. Verify only the Ruby scheduler owns the retained category.
Jobs and schedules: Keep Redis and qualify Exq consumers
Inspect the source
A retained Redis broker may carry Sidekiq/Resque-shaped jobs; framework wrappers, class names, serializer tags and version-sensitive timestamps are still part of the execution contract.
During coexistence
Recommendation, broker-retaining replacement path: qualify Exq for selected job types on isolated queues. Keep unsupported Ruby types on Ruby consumers; map only deliberately supported payload versions, and give each category one consumer family and schedule owner.
Target design
Selected Elixir workers using Exq's documented Redis-backed Resque/Sidekiq-compatible format. This is a candidate for qualification, not a claim that arbitrary Active Job payloads are interoperable.
Rollback
Recommendation: stop new consumption and return only backward-readable queued work to Ruby; preserve both consumers for payloads accepted during the transition.
Benefits and prerequisites
Recommendation: selected job execution can move to Elixir while preserving the broker boundary.
Requires: Fixture-tested serialization, queue isolation, retry mapping and scheduler ownership.
Tradeoffs: Redis remains; compatibility and unsupported Ruby argument types require explicit maintenance.
Checks before transfer
- Replay ordinary arguments, an Active Job wrapper, serializer edge cases and scheduled/retry payloads; reject unsupported cases without consuming them silently.
- Crash after a business effect before acknowledgement and verify replay safety; confirm old and new consumers never race for an unqualified category.
Jobs and schedules: Run Oban SQL workers alongside legacy queues
Inspect the source
Legacy Redis jobs and a proposed SQL queue have distinct payload/storage formats and retry/schedule state. A backend change does not copy the backlog or the recurring schedule.
During coexistence
Recommendation, SQL replacement path: run Oban alongside the legacy broker and route selected categories exclusively to one system. Keep old ready, retry, delayed, failed and running work accounted for. Transfer each schedule once; use a recoverable relay/outbox while domain data and queue insertion span stores.
Target design
Oban workers on the chosen supported SQL engine. With the same Repo/transaction, Oban.insert in Ecto.Multi can join domain changes; a separate database cannot gain that atomicity merely from both databases being SQL.
Rollback
Recommendation: pause new producers/consumption, keep accepted Oban payloads executable, and reconcile effects before moving routing back. Do not blindly copy all rows into the old broker.
Benefits and prerequisites
Atomic domain-write-and-job-insert is available within a shared transaction.
Requires: One supported database transaction/Repo for both writes and business idempotency for execution.
Tradeoffs: Queue load shares the database; SQL atomic insertion does not guarantee exactly-once external effects.
Recommendation: broker retirement can reduce the operated service inventory.
Requires: All Redis uses transferred, all backlog states reconciled and recovery/rollback checks passed.
Tradeoffs: Redis plus SQL coexistence temporarily adds operational work; no service reduction occurs while Redis remains needed.
Checks before transfer
- Rollback the combined transaction and confirm neither domain change nor executable Oban job remains.
- Pause a selected Oban queue, reconcile running work and inspect retained backlog; resume without duplicated effects.
- Restart during a job and validate the selected engine's configured recovery policy, including a failure after an external side effect.
Identity and authorization
Inspect the source
Record old cookie encoding, serializer, keys/salts, expiration and session revocation; shared account IDs alone do not establish cookie compatibility. Plug COOKIE defaults its serializer to external_term_format and exposes rotating cryptographic options.
During coexistence
Recommendation: retain the existing identity authority through a qualified session exchange or compatibility decoder. Map authorization rules into Phoenix contexts and LiveView mount/events; keep account and revocation ownership explicit.
Target design
Phoenix identity with the selected session store and LiveView authorization in mount/on_mount and actions. Recommendation: choose planned reauthentication when cookie compatibility is not worth maintaining.
Rollback
Recommendation: retain the old decoder/exchange until routing can return; never reverse revocation merely to restore traffic.
Benefits and prerequisites
Recommendation: users can preserve access while a connected feature moves.
Requires: Qualified decoder/exchange, shared revocation and event-level authorization.
Tradeoffs: Long-lived sockets need explicit disconnect/recheck behavior when access changes; sharing secrets alone is insufficient.
Checks before transfer
- Login through the old runtime, access the target feature, revoke the account/session and confirm HTTP plus existing/reconnected LiveView access follows the required policy.
- Send a forged delete event for another tenant despite a hidden UI control; confirm the server rejects it.
Realtime transport
Inspect the source
Action Cable, Phoenix Channels and LiveView are different protocols. Capture subscription identity, event envelope, authorization, ordering and missed-message recovery. Channels documents at-most-once client delivery without server persistence.
During coexistence
Recommendation: retain old client endpoints and bridge versioned domain events into each renderer. A room/tenant cohort owns its subscriptions and reconnects. Choose Redis PubSub or a qualified distributed-Elixir cluster deliberately; sharing Redis does not translate the wire protocol.
Target design
LiveView for connected server-owned screens or Channels for explicit realtime clients, with durable domain state and an application catch-up mechanism when missed events matter.
Rollback
Recommendation: preserve the old endpoint/event envelope and cohort routing through reconnects; rebuild UI from persisted state instead of duplicating broadcasts.
Benefits and prerequisites
Recommendation: connected UI and domain operations can share Phoenix contexts.
Requires: Authorized subscriptions, working multi-node fanout and persisted state/cursors for recovery requirements.
Tradeoffs: Live protocol/client changes and cluster operations remain; PubSub does not supply a durable user-message history.
Checks before transfer
- Place old/new subscribers on separate nodes; commit through either permitted path and verify every authorized recipient converges once.
- Disconnect before an event, restart a node, reconnect with the chosen cursor/state mechanism and verify missed domain changes recover; test revocation while connected.
Caching and shared state
Inspect the source
Classify every Redis use as cache, session, limiter, lock, job or PubSub. ETS tables are node-local and their ownership lifetime matters; they do not provide Redis's cross-node boundary.
During coexistence
Recommendation: move only reconstructible cache entries into supervised local ownership, with explicit TTL/invalidation and bounded memory. Keep shared identity, coordination, queues and broadcast infrastructure until their own transitions qualify.
Target design
ETS for deliberately local reconstructed values, or a retained shared cache where consistency across nodes is required. Recommendation: state stale-read tolerance and rebuilding behavior in the application contract.
Rollback
Recommendation: switch those reads back to the qualified shared store or authoritative data; retain Redis until every remaining capability is reconciled.
Benefits and prerequisites
Recommendation: a local cache can remove a remote dependency from selected reads.
Requires: Acceptable node-local semantics, bounded memory and verified invalidation/rebuild behavior.
Tradeoffs: Each node maintains separate contents; owner/node failure loses local state. Performance benefit requires measurement.
Checks before transfer
- Warm two nodes, update the authoritative record and verify their documented staleness/invalidation policy.
- Terminate the table owner or restart the node; verify the application rebuilds and no durable job/session/lock state was stored there.
Delivery and recovery
Inspect the source
Record endpoint, worker, scheduler, Repo, assets and cluster/PubSub ownership. Phoenix runtime configuration, release build and schema migrations have distinct deployment steps.
During coexistence
Recommendation: maintain both releases with stable cohort routing and a single schedule/writer owner per responsibility. Monitor queue age, retry effects, node connectivity and authorization failures against application-specific promotion thresholds.
Target design
A Phoenix release with runtime.exs configuration, built assets, named migration runner and supervised workers. Recommendation: make cluster formation, backups and restore ordering explicit instead of assuming VM startup establishes them.
Rollback
Recommendation: retain the previous release and compatible database reads; return cohort routing and role ownership separately, reconciling new jobs and external effects.
Benefits and prerequisites
Recommendation: explicit supervised roles and release inputs make restart behavior reviewable.
Requires: Configured children, deployment inventory and exercised recovery procedures.
Tradeoffs: Durable recovery still depends on the chosen databases/queues; supervision alone cannot recreate lost external state.
Checks before transfer
- Start the actual release with a disposable restored database and confirm assets, authenticated routes, a queued job and cross-node broadcast work.
- Stop a worker/node, observe detection and recovery, and verify no second schedule owner activates during rollback.
Setup
- Read README.md, mix.exs, mix.lock and runtime pins; preserve existing applications. This is a recipe, not executed setup evidence.
- For a new project, choose an empty source directory in a local development workspace. Check elixir --version, mix --version, mix phx.new --version and actual PostgreSQL connectivity; install only missing prerequisites using official instructions.
- Resolve and record a compatible Elixir/OTP pair and Phoenix generator. Generate with mix phx.new my_app --database postgres; honor generated guidance. Use --no-agents-md only when the repository explicitly adopts a README-only instruction policy.
- If dependency guidance synchronization is useful, add usage_rules as a development dependency, configure selected rules in mix.exs and review mix usage_rules.sync output. Honor generated Phoenix guidance; configure an alternate file only for an explicit repository policy.
- Enter my_app; configure development database credentials outside committed secrets; inspect and run mix setup. For API-only creation use the documented --no-html --no-assets options instead.
- If accounts are required, run mix phx.gen.auth Accounts User users --live, then mix deps.get and mix ecto.migrate; review generated instructions and email setup.
- If jobs are required, follow the installed Oban installation/migration instructions, supervise Oban and configure bounded queues; write idempotent workers and tests.
- Add selected development/test checks only. For PhoenixTest.Playwright install its JS dependency and matching browsers, configure test endpoint and SQL sandbox as documented.
- Run the checks below and actual browser flows. Fix failures in place, retaining logs; never regenerate over work to hide a failure.
- For deployment qualification, follow Phoenix releases: generate release helpers, compile production assets and build a target-compatible release. Rehearse migration, startup, reconnect, job retry and backup/restore on the selected host before claiming production readiness.
- Completion: record exact versions, lockfile, checks and observed flows in README-linked evidence; report untested deployment/mobile paths explicitly.
Verification
Run these in the configured application; they are instructions, not recorded passes.
mix hex.audit mix format --check-formatted mix compile --warnings-as-errors mix test mix credo --strict # only after installing/configuring Credo mix sobelow --strict --exit low # only after installing/configuring Sobelow; review findings mix dialyzer # optional, after Dialyxir/PLT configuration mix phx.server # interactive smoke check, not an automated assertion MIX_ENV=prod mix assets.deploy # release qualification, after production prerequisites MIX_ENV=prod mix release # after release configuration; not deployment proof
Open questions
- Does the product fit connected server-owned UI, or need a separate offline/native client?
- Which account/tenant permissions and email recovery requirements apply?
- Which work needs durable retries and duplicate-effect protection?
- Which host, object storage, observability and backup/restore requirements apply?
Sources
- Phoenix application generator
- Phoenix LiveView
- LiveView JavaScript interoperability
- Ecto
- Phoenix authentication generator
- LiveView security model
- Oban
- Oban testing
- ExUnit
- LiveViewTest
- Ecto SQL Sandbox
- PhoenixTest.Playwright
- Credo
- Dialyxir
- Sobelow
- Hex dependency audit
- Phoenix releases
- Phoenix JSON and APIs
- LiveView Native source README
- Swoosh
- LiveView uploads
- Phoenix PubSub
- usage_rules README
- usage_rules sync task
- Ecto current transaction API and semantics
Extended Elixir reference
The full Markdown and JSON include the attributed Elixir Menu optional libraries, runtime and other application paths. Read the maintained Elixir Menu reference.