Deploying a Phoenix App with Elixir on Deployxa: A Complete Guide | Deployxa

Phoenix is the leading Elixir web framework, known for real-time features and performance. Here is how to deploy a Phoenix app on Deployxa.

← Back to Dispatch Articles
Engineering Log

Deploying a Phoenix App with Elixir on Deployxa: A Complete Guide

Phoenix is the leading Elixir web framework, known for real-time features and performance. Here is how to deploy a Phoenix app on Deployxa.

Deploying a Phoenix App with Elixir on Deployxa

Key Facts

  • Direct answer: The direct answer is that Deployxa auto-detects Phoenix from your `mix.exs` (which includes `phoenix`). It configures the build and start commands: the build command is `mix deps.get && mix compile && mix release`, the start command is `_build/prod/rel/myapp/bin/myapp start`, and the runtime is Elixir 1.16 with Erlang 26.

  • Why Phoenix Is a Great Choice for Realtime Apps: Three reasons explain why Phoenix is a great choice for realtime apps.

  • The Architecture: Phoenix + Erlang VM + Container: Here is how Deployxa deploys a Phoenix app.

  • Step-by-Step: Deploying a Phoenix App: Here is the exact workflow for a typical Cursor-generated Phoenix app.

  • Performance: Phoenix vs Node.js vs Go: Phoenix, Node.js, and Go are three leading choices for realtime apps.

Phoenix is the leading Elixir web framework, known for its real-time features (via LiveView and Channels) and excellent performance (via the Erlang VM). It is a favorite of teams building realtime apps (chat, collaboration, dashboards) and high-traffic APIs. But deploying Phoenix has traditionally required writing a Dockerfile (to compile the Elixir code and run it with the Erlang VM), configuring the release, and handling the database connection. Deployxa's zero-config engine eliminates all of that, detecting Phoenix from your `mix.exs` and configuring the deployment. Here is how to deploy a Phoenix app on Deployxa.

The direct answer is that Deployxa auto-detects Phoenix from your `mix.exs` (which includes `phoenix`). It configures the build and start commands: the build command is `mix deps.get && mix compile && mix release`, the start command is `_build/prod/rel/myapp/bin/myapp start`, and the runtime is Elixir 1.16 with Erlang 26. You do not write a Dockerfile, you do not configure the release manually, and you do not manage the Erlang VM. The platform handles all of it, just as it does for Spring Boot and Flask apps.

Why Phoenix Is a Great Choice for Realtime Apps

Three reasons explain why Phoenix is a great choice for realtime apps. First, its LiveView feature lets you build realtime, interactive UIs without writing JavaScript, which is a significant productivity boost. For apps that need realtime features (chat, collaboration, dashboards), LiveView is hard to beat. Second, its Channels feature (built on the Erlang VM's process model) handles millions of concurrent WebSocket connections, which makes Phoenix ideal for high-concurrency realtime apps. Third, its performance is excellent. The Erlang VM is designed for high-concurrency, fault-tolerant systems, which means Phoenix apps are fast and reliable. For more on realtime features, see our article on running long-lived WebSockets in Node.js and Go.

The Architecture: Phoenix + Erlang VM + Container

Here is how Deployxa deploys a Phoenix app.

The Phoenix container

The ingestion service detects Phoenix from your `mix.exs`. It configures the build and start commands:

- Build command: `mix deps.get && mix compile && mix release`

- Start command: `_build/prod/rel/myapp/bin/myapp start`

- Runtime: Elixir 1.16 with Erlang 26

The release configuration

Phoenix releases are self-contained packages that include the compiled code, the Erlang VM, and all dependencies. The release is configured via `config/runtime.exs`, which reads environment variables at runtime.

The reverse proxy

Traefik v3 routes traffic from your custom domain to the Phoenix container, with automatic SSL via Let's Encrypt.

Step-by-Step: Deploying a Phoenix App

Here is the exact workflow for a typical Cursor-generated Phoenix app.

Step 1: Create your Phoenix app

```bash

mix phx.new my_app

cd my_app

mix deps.get

```

Step 2: Configure runtime.exs

```elixir

config/runtime.exs

import Config

if config_env() == :prod do

database_url = System.get_env("DATABASE_URL") ||

raise "DATABASE_URL is not set"

secret_key_base = System.get_env("SECRET_KEY_BASE") ||

raise "SECRET_KEY_BASE is not set"

config :my_app, MyApp.Repo,

url: database_url,

pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")

config :my_app, MyAppWeb.Endpoint,

server: true,

url: [host: System.get_env("PHX_HOST") || "localhost", port: 443, scheme: "https"],

http: [ip: {0, 0, 0, 0}, port: String.to_integer(System.get_env("PORT") || "4000")],

secret_key_base: secret_key_base

end

```

Step 3: Create a simple controller

```elixir

lib/my_app_web/controllers/page_controller.ex

defmodule MyAppWeb.PageController do

use MyAppWeb, :controller

def index(conn, _params) do

json(conn, %{message: "Hello, World!"})

end

def health(conn, _params) do

json(conn, %{status: "ok"})

end

end

```

Step 4: Add routes

```elixir

lib/my_app_web/router.ex

defmodule MyAppWeb.Router do

use MyAppWeb, :router

pipeline :api do

plug :accepts, ["json"]

end

scope "/", MyAppWeb do

pipe_through :api

get "/", PageController, :index

get "/health", PageController, :health

end

end

```

Step 5: Push to GitHub

```bash

git init

git add .

git commit -m "phoenix app"

git remote add origin https://github.com/yourname/my_app.git

git push -u origin main

```

Step 6: Connect to Deployxa

In the Deployxa dashboard, connect your repository. Deployxa auto-detects Phoenix:

```text

[ingest] Detected Elixir project

[ingest] Framework: phoenix

[ingest] Runtime: elixir 1.16, erlang 26

[ingest] Build command: mix deps.get && mix compile && mix release

[ingest] Start command: _build/prod/rel/my_app/bin/my_app start

[ingest] Port: $PORT

```

Step 7: Configure environment variables

In the Deployxa dashboard, add:

- `DATABASE_URL`: your Postgres connection string (e.g., `ecto://user:pass@host:5432/myapp`)

- `SECRET_KEY_BASE`: a strong secret (generate with `mix phx.gen.secret`)

- `PHX_HOST`: your app's domain (e.g., `myapp.com`)

The pre-flight scanner will warn you if any are missing. For more on environment variables, see our article on the vibe coder's guide to environment variables.

Step 8: Deploy

Click Deploy. The build compiles the Elixir code and creates a release, the container starts the release, and your app is live within 60 to 90 seconds.

Step 9: Add a custom domain

Add a custom domain in the Deployxa dashboard. SSL is provisioned automatically.

Step 10: Verify with deployxa doctor

Run `deployxa doctor` to verify health. The 14-point readiness engine checks SSL, DNS, environment variables, health endpoints, and container status.

Common Pitfalls and Troubleshooting

The first pitfall is the `PORT` environment variable. Phoenix apps typically listen on port 4000 by default, but Deployxa assigns a dynamic port via the `PORT` environment variable. The fix is to set `http: [ip: {0, 0, 0, 0}, port: String.to_integer(System.get_env("PORT") || "4000")]` in `runtime.exs`. The second pitfall is the `SECRET_KEY_BASE`. Phoenix requires a strong secret key base in production, which AI assistants often leave as a default or weak value. The fix is to generate a strong secret with `mix phx.gen.secret` and set it as the `SECRET_KEY_BASE` environment variable. The third pitfall is the database URL format. Phoenix uses Ecto, which uses a different URL format from other frameworks (e.g., `ecto://` instead of `postgresql://`). The fix is to use the Ecto format in your `DATABASE_URL` environment variable. The fourth pitfall is the release configuration. Phoenix releases need to be configured via `config/runtime.exs` (not `config/prod.exs`), because `runtime.exs` is evaluated at runtime (when environment variables are available). The fix is to put your environment-variable-dependent configuration in `runtime.exs`. The fifth pitfall is the Erlang cookie. Phoenix releases use an Erlang cookie for clustering, which needs to be set consistently across all instances. The fix is to set the `ERL_AFLAGS` environment variable with the cookie (e.g., `-setcookie my-cookie`).

Performance: Phoenix vs Node.js vs Go

Phoenix, Node.js, and Go are three leading choices for realtime apps. Phoenix (via the Erlang VM) handles millions of concurrent WebSocket connections, which makes it ideal for high-concurrency realtime apps. Node.js handles thousands of concurrent connections (via the event loop), which is sufficient for most apps. Go handles tens of thousands of concurrent connections (via goroutines), which is between Phoenix and Node.js. For high-concurrency realtime apps, Phoenix is the best choice. For apps that need the Node.js ecosystem, Node.js is the better choice. For apps that need maximum performance and efficiency, Go is the better choice. Deployxa supports all three equally, with the AutoRepairService and the zero-config engine handling each framework automatically. For more on performance, see our article on SPA vs SSR hardware sizing. For more on realtime features, see our article on running long-lived WebSockets.

Advanced Phoenix Patterns

Beyond the basics, Phoenix apps benefit from several advanced patterns. The first is LiveView. LiveView lets you build realtime, interactive UIs without writing JavaScript, which is a significant productivity boost. The second is Channels. Channels (built on the Erlang VM's process model) handle millions of concurrent WebSocket connections, which makes Phoenix ideal for high-concurrency realtime apps. The third is Ecto. Ecto is Phoenix's database wrapper, which provides a DSL for queries and migrations. The fourth is Phoenix Presence. Presence tracks which users are online, which is useful for chat apps and collaboration tools. The fifth is testing. Phoenix has excellent testing support (via `ExUnit`), which makes it easy to write unit and integration tests. For more on testing, see our article on the testing void. For more on Phoenix deployment, see our articles on deploying a Ruby on Rails app and deploying a Flask app with Gunicorn.

Scaling and Long-Term Considerations

As your project grows beyond the initial deployment, several long-term considerations become important. The first is scalability planning. What works for 100 users might not work for 1000 or 10000 users. Plan ahead by understanding your bottlenecks: is it the database (add indexes, use read replicas), the app server (add containers, use auto-scaling), or the network (use a CDN, optimize assets)? Monitor your resource usage trends and scale proactively before you hit limits, not reactively after an outage. For more on scaling, see our article on how to scale your SaaS from MVP to first customers.

The second consideration is maintainability. As your codebase grows, technical debt accumulates. Regular refactoring, dependency updates, and code reviews keep the codebase healthy. Schedule time for maintenance (e.g., one day per month) and treat it as a feature, not an afterthought. For more on maintenance, see our article on the SaaS founder's guide to dependency management.

The third consideration is team growth. What happens when you hire your first engineer? Is the codebase understandable? Is the deployment process documented? Are the environment variables inventoried? A well-documented, well-structured project makes onboarding faster and reduces the risk of mistakes. For more on team handoff, see our article on how to build a deployment process your future team can inherit.

The fourth consideration is cost evolution. As you scale, costs increase. Without monitoring, costs can exceed revenue. Track your cost-per-user metric (total hosting cost / number of active users) and ensure it stays below your revenue-per-user. For more on cost management, see our article on the SaaS founder's guide to cost optimization.

The fifth consideration is disaster recovery. As you grow, the impact of data loss or downtime increases. Regularly test your backup restore, your rollback procedure, and your incident response plan. An untested plan is not a plan. For more on disaster recovery, see our article on the SaaS founder's guide to disaster recovery planning.

Conclusion: Phoenix Without the Configuration

Phoenix is the leading Elixir web framework, and deploying it should be as simple as pushing to Git. Deployxa's zero-config engine makes it so: no Dockerfile, no release configuration, no Erlang VM management. Stop configuring releases and start shipping.

Ready to deploy your Phoenix app? Drag your project to Deployxa Drop for an instant live preview, or install the CLI with `npm i -g @deployxa/cli` and deploy from your terminal. For more on framework deep-dives, see our articles on deploying a Spring Boot app and deploying an Express app with PM2. Learn about deploying a Ruby on Rails app and deploying a Flask app with Gunicorn in our companion articles. Explore our free developer tools to speed up your workflow.

Ready to deploy with Deployxa?

Deploy your apps globally with automatic SSL and AI diagnostics.

Start Free Now