Phoenix Operations and Deployment (Elixir/BEAM)
Production-ready Phoenix apps rely on releases, runtime configuration, telemetry, clustering, and secure endpoints. The BEAM enables rolling restarts and supervision resilience when configured correctly.
Releases and Runtime Config
MIX_ENV=prod PHX_SERVER=true mix assets.deploy
MIX_ENV=prod mix release
_build/prod/rel/my_app/bin/my_app eval "IO.puts(:os.type())"
_build/prod/rel/my_app/bin/my_app start
config/runtime.exs for env-driven settings:
config :my_app, MyApp.Repo,
url: System.fetch_env!("DATABASE_URL"),
pool_size: String.to_integer(System.get_env("POOL_SIZE", "10")),
ssl: true
config :my_app, MyAppWeb.Endpoint,
url: [host: System.fetch_env!("PHX_HOST"), port: 443, scheme: "https"],
http: [ip: {0,0,0,0}, port: String.to_integer(System.get_env("PORT", "4000"))],
secret_key_base: System.fetch_env!("SECRET_KEY_BASE"),
server: true
Secrets
- Prefer env vars or secret stores (AWS/GCP KMS, Vault); avoid embedding in configs.
- Generate
SECRET_KEY_BASE with mix phx.gen.secret.
Clustering and PubSub/Presence
Add libcluster for automatic node discovery:
# mix.exs deps
{:libcluster, "~> 3.3"},
{:phoenix_pubsub, "~> 2.1"},
# application.ex
topologies = [
dns_poll: [
strategy: Cluster.Strategy.DNSPoll,
config: [poll_interval: 5_000, query: "my-app.internal"],
connect: {:net_adm, :ping}
]
]
children = [
{Cluster.Supervisor, [topologies, [name: MyApp.ClusterSupervisor]]},
{Phoenix.PubSub, name: MyApp.PubSub},
MyAppWeb.Endpoint
]
Guidelines
- Share
secret_key_base across nodes for consistent session signing.
- Use distributed PubSub for Presence; ensure node connectivity before enabling Presence-heavy features.
- For blue/green, keep cookies compatible between versions.
Telemetry, Logging, and Metrics
- Install
opentelemetry_phoenix and opentelemetry_ecto for traces/metrics.
- Add
Plug.Telemetry and LoggerJSON or structured logging.
- Export metrics (Prometheus/OpenTelemetry) via
:telemetry_poller for VM stats (reductions, memory, schedulers).
- Set
LOGGER_LEVEL=info in prod; use :debug only for troubleshooting.
HTTP and Network Hardening
- Enforce HTTPS (
force_ssl), HSTS, secure cookies (same_site, secure), and proper content_security_policy.
- CORS: configure
cors_plug for API origins.
- Rate limiting: apply plugs (ETS/Cachex token bucket) or edge (NGINX/Cloudflare).
- Uploads: prefer presigned URLs; limit request body size (
:max_request_line_length, :max_header_value_length).
Assets and Static Delivery
mix assets.deploy runs npm/tailwind/esbuild and digests assets.
- Serve static files via CDN/reverse proxy; ensure
cache-control headers set in Endpoint.
- Disable unused watchers in production to trim image size.
Background Jobs
- Oban recommended for retries/backoff, scheduled jobs, and isolation; supervise in
application.ex.
- Configure queues via runtime env; monitor with Oban Web/Pro or telemetry.
- For CPU-heavy tasks, consider pooling or external workers to avoid blocking schedulers.
Deployment Patterns
- Containers: multi-stage builds; run
mix deps.get --only prod, mix compile, mix assets.deploy, then mix release.
- Systemd: run release binary as service with
Environment= secrets; add Restart=on-failure.
- Fly/Gigalixir/Render: supply env vars, attach Postgres/Redis, open long-lived WebSocket ports.
- Blue/green or canary: keep DB migrations compatible; deploy code first, then run migrations; keep feature flags for schema changes.
Observability and Health
- Add
/health and /ready endpoints (Repo check + PubSub/Presence check).
- Export VM metrics: run
:telemetry_poller for scheduler utilization and memory.
- Alert on error rates, DB timeouts, queue depths, and VM memory.
Common Pitfalls
- Building releases without
PHX_SERVER=true (endpoint won’t start).
- Missing runtime config in
config/runtime.exs; relying on compile-time config for secrets.
- No cluster discovery configured → Presence inconsistencies across nodes.
- Leaving default
secret_key_base or per-node keys → invalid sessions after deploy.
- Large assets without digests/CDN → slow cold loads.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: bobmatnyc-claude-mpm-skills-phoenix-ops3description: Phoenix Operations and Deployment (Elixir/BEAM)4---56# Phoenix Operations and Deployment (Elixir/BEAM)78Production-ready Phoenix apps rely on releases, runtime configuration, telemetry, clustering, and secure endpoints. The BEAM enables rolling restarts and supervision resilience when configured correctly.910## Releases and Runtime Config1112```bash13MIX_ENV=prod PHX_SERVER=true mix assets.deploy14MIX_ENV=prod mix release15_build/prod/rel/my_app/bin/my_app eval "IO.puts(:os.type())"16_build/prod/rel/my_app/bin/my_app start17```1819`config/runtime.exs` for env-driven settings:20```elixir21config :my_app, MyApp.Repo,22 url: System.fetch_env!("DATABASE_URL"),23 pool_size: String.to_integer(System.get_env("POOL_SIZE", "10")),24 ssl: true2526config :my_app, MyAppWeb.Endpoint,27 url: [host: System.fetch_env!("PHX_HOST"), port: 443, scheme: "https"],28 http: [ip: {0,0,0,0}, port: String.to_integer(System.get_env("PORT", "4000"))],29 secret_key_base: System.fetch_env!("SECRET_KEY_BASE"),30 server: true31```3233**Secrets**34- Prefer env vars or secret stores (AWS/GCP KMS, Vault); avoid embedding in configs.35- Generate `SECRET_KEY_BASE` with `mix phx.gen.secret`.3637## Clustering and PubSub/Presence3839Add `libcluster` for automatic node discovery:40```elixir41# mix.exs deps42{:libcluster, "~> 3.3"},43{:phoenix_pubsub, "~> 2.1"},4445# application.ex46topologies = [47 dns_poll: [48 strategy: Cluster.Strategy.DNSPoll,49 config: [poll_interval: 5_000, query: "my-app.internal"],50 connect: {:net_adm, :ping}51 ]52]5354children = [55 {Cluster.Supervisor, [topologies, [name: MyApp.ClusterSupervisor]]},56 {Phoenix.PubSub, name: MyApp.PubSub},57 MyAppWeb.Endpoint58]59```6061**Guidelines**62- Share `secret_key_base` across nodes for consistent session signing.63- Use distributed PubSub for Presence; ensure node connectivity before enabling Presence-heavy features.64- For blue/green, keep cookies compatible between versions.6566## Telemetry, Logging, and Metrics6768- Install `opentelemetry_phoenix` and `opentelemetry_ecto` for traces/metrics.69- Add `Plug.Telemetry` and `LoggerJSON` or structured logging.70- Export metrics (Prometheus/OpenTelemetry) via `:telemetry_poller` for VM stats (reductions, memory, schedulers).71- Set `LOGGER_LEVEL=info` in prod; use `:debug` only for troubleshooting.7273## HTTP and Network Hardening7475- Enforce HTTPS (`force_ssl`), HSTS, secure cookies (`same_site`, `secure`), and proper `content_security_policy`.76- CORS: configure `cors_plug` for API origins.77- Rate limiting: apply plugs (ETS/Cachex token bucket) or edge (NGINX/Cloudflare).78- Uploads: prefer presigned URLs; limit request body size (`:max_request_line_length`, `:max_header_value_length`).7980## Assets and Static Delivery8182- `mix assets.deploy` runs npm/tailwind/esbuild and digests assets.83- Serve static files via CDN/reverse proxy; ensure `cache-control` headers set in Endpoint.84- Disable unused watchers in production to trim image size.8586## Background Jobs8788- Oban recommended for retries/backoff, scheduled jobs, and isolation; supervise in `application.ex`.89- Configure queues via runtime env; monitor with Oban Web/Pro or telemetry.90- For CPU-heavy tasks, consider pooling or external workers to avoid blocking schedulers.9192## Deployment Patterns9394- **Containers**: multi-stage builds; run `mix deps.get --only prod`, `mix compile`, `mix assets.deploy`, then `mix release`.95- **Systemd**: run release binary as service with `Environment=` secrets; add `Restart=on-failure`.96- **Fly/Gigalixir/Render**: supply env vars, attach Postgres/Redis, open long-lived WebSocket ports.97- **Blue/green or canary**: keep DB migrations compatible; deploy code first, then run migrations; keep feature flags for schema changes.9899## Observability and Health100101- Add `/health` and `/ready` endpoints (Repo check + PubSub/Presence check).102- Export VM metrics: run `:telemetry_poller` for scheduler utilization and memory.103- Alert on error rates, DB timeouts, queue depths, and VM memory.104105## Common Pitfalls106107- Building releases without `PHX_SERVER=true` (endpoint won’t start).108- Missing runtime config in `config/runtime.exs`; relying on compile-time config for secrets.109- No cluster discovery configured → Presence inconsistencies across nodes.110- Leaving default `secret_key_base` or per-node keys → invalid sessions after deploy.111- Large assets without digests/CDN → slow cold loads.112113---114> Converted and distributed by [TomeVault](https://tomevault.io/claim/bobmatnyc) — claim your Tome and manage your conversions.115<!-- tomevault:4.0:skill_md:2026-04-11 -->