Elixir Runtime
Host Elixir applications on Witchly.host with Mix. Deploy from Git, run Phoenix apps, GenServers, or classic OTP releases.
languages (12 articles)
On This Page
Elixir Runtime
Elixir is a functional, concurrent, high-level language running on the BEAM virtual machine (the same VM as Erlang). It shines at highly-concurrent systems — chat servers, real-time dashboards, Phoenix web apps, GenServer-based workers, and OTP releases. Witchly runs the latest Elixir.
When to pick Elixir
- You’re building a real-time system (Phoenix LiveView, PubSub, websockets).
- You need fault tolerance — supervision trees keep your app alive through crashes.
- You want excellent concurrency primitives without fighting threads.
Quick deploy
- dash.witchly.host → Deploy → Languages → Elixir.
- On the Startup tab, set
Git Repository Addressto your repo URL. - Start — first boot runs
mix deps.getthenmix run --no-halt.
Startup flow
if [[ -d .git ]] && [[ {{AUTO_UPDATE}} == "1" ]]; then git pull; fi
mix deps.get
mix run --no-halt
mix run --no-halt starts your app and keeps the BEAM running. For Phoenix, you’ll want to customize this (see below).
Variables reference
| Variable | Purpose |
|---|---|
GIT_ADDRESS | Git repo URL |
GIT_BRANCH | Git branch |
USER_UPLOAD | 1 to skip clone |
AUTO_UPDATE | 1 to git pull on each start |
GIT_USERNAME, GIT_ACCESS_TOKEN | Private repo credentials |
Phoenix app
For a Phoenix project, override the startup command:
if [[ -d .git ]] && [[ {{AUTO_UPDATE}} == "1" ]]; then git pull; fi
mix deps.get --only prod
MIX_ENV=prod mix compile
MIX_ENV=prod mix assets.deploy
MIX_ENV=prod PORT=${SERVER_PORT} mix phx.server
Make sure your config/runtime.exs reads from env:
config :my_app, MyAppWeb.Endpoint,
http: [ip: {0, 0, 0, 0}, port: String.to_integer(System.get_env("PORT") || "4000")],
secret_key_base: System.get_env("SECRET_KEY_BASE")
OTP releases (recommended for production)
For small, fast, reproducible deploys, build an OTP release:
# Locally or in CI
MIX_ENV=prod mix release
# Creates _build/prod/rel/my_app/
Tar the release, SFTP it to /home/container/, extract, then set the startup to:
./bin/my_app start
OTP releases don’t need Elixir/Mix installed — they’re self-contained BEAM binaries.
Discord bot with Nostrum
# lib/my_bot/consumer.ex
defmodule MyBot.Consumer do
use Nostrum.Consumer
alias Nostrum.Api
def handle_event({:MESSAGE_CREATE, msg, _ws}) do
case msg.content do
"!ping" -> Api.create_message(msg.channel_id, "pong")
_ -> :ignore
end
end
end
# mix.exs
defp deps do
[{:nostrum, "~> 0.9"}]
end
Managing state
Elixir shines with GenServers, Supervisors, and ETS. If you’re storing app state in memory, make sure it’s under a Supervisor so crashes are handled gracefully.
For persistent state, pair with Postgres + Ecto.
Troubleshooting
mix: command not found— confirm the Elixir image is fully built; the first deploy can take a minute to be ready.- Port not accessible — bind explicitly to
0.0.0.0in config, notlocalhost/127.0.0.1. - Hot code reload not working — reloads in dev only; use a staging server with auto-update for dev-like experience.