A Heroku buildpack for Elixir and Erlang/OTP. Supports stacks heroku-22, heroku-24, and heroku-26.
| Stack | Ubuntu | OTP minimum | OTP latest confirmed | Elixir minimum |
|---|---|---|---|---|
| heroku-22 | 22.04 LTS | 24.2 | 29.1.1 | 1.12 |
| heroku-24 | 24.04 LTS | 24.3.4 | 29.1.1 | 1.12 |
| heroku-26 | 26.04 LTS | 26.0 | 29.1.1 | 1.15 |
OTP binaries are provided by hex.pm builds. Elixir binaries are provided by hex.pm builds.
heroku buildpacks:set https://github.com/heroku-johnny/buildpack-elixirCreate elixir_buildpack.config in your project root. Both erlang_version and
elixir_version are required — the buildpack will not guess defaults.
erlang_version=29.1.1
elixir_version=1.20.4git push heroku mainAll options go in elixir_buildpack.config in the root of your repository.
| Option | Required | Default | Description |
|---|---|---|---|
erlang_version |
yes | — | Erlang/OTP version to install (e.g. 27.2) |
elixir_version |
yes | — | Elixir version to install (e.g. v1.18.3) |
always_rebuild |
no | false |
Set true to clear the build cache on every deploy |
release |
no | false |
Set true to run mix release --overwrite after compile |
runtime_path |
no | /app |
Path where Erlang and Elixir are installed at runtime |
hook_pre_fetch_dependencies |
no | — | Shell command to run before mix deps.get |
hook_pre_compile |
no | — | Shell command to run before mix compile |
hook_compile |
no | — | Shell command to replace mix compile entirely |
hook_post_compile |
no | — | Shell command to run after compile |
Browse available OTP versions for your stack:
- heroku-22 (ubuntu-22.04): https://builds.hex.pm/builds/otp/ubuntu-22.04/builds.txt
- heroku-24 (ubuntu-24.04): https://builds.hex.pm/builds/otp/ubuntu-24.04/builds.txt
- heroku-26 (ubuntu-26.04): https://builds.hex.pm/builds/otp/ubuntu-26.04/builds.txt
Browse available Elixir versions: https://builds.hex.pm/builds/elixir/builds.txt
Hooks are shell commands that run at specific points in the build pipeline. Set them
in elixir_buildpack.config. They run inside the build directory with GIT_DIR unset.
# Install Node.js assets before compile (Phoenix apps)
hook_pre_compile="npm run deploy --prefix assets"
# Run a custom compile command instead of mix compile
hook_compile="mix compile --warnings-as-errors"
# Run a script after compile
hook_post_compile="bash .buildpack/post_compile.sh"If a hook command exits with a non-zero status, the build fails immediately with an error message naming the hook and the command that failed.
Set release=true to build a Mix release after compile:
erlang_version=29.1.1
elixir_version=1.20.4
release=trueThe buildpack runs mix release --overwrite. Your mix.exs must define a release
configuration. See the Mix release docs.
This buildpack supports Heroku CI via the standard testpack API.
Set your test command in app.json:
{
"environments": {
"test": {
"buildpacks": [
{ "url": "https://github.com/heroku-johnny/buildpack-elixir" }
]
}
}
}By default the buildpack runs mix test. Override with the test_args config variable:
# In ENV_VARS or app.json environment config
TEST_ARGS="--only integration"The test environment sets MIX_ENV=test automatically.
The buildpack caches Erlang, Elixir, and Mix dependencies between builds. The cache is keyed by stack, OTP version, and Elixir version (including OTP major). Changing any of these automatically invalidates the relevant cache layer.
Force a full cache clear on the next build:
# In elixir_buildpack.config
always_rebuild=trueReset it to false after the build completes, or the cache will be cleared on every
subsequent deploy.
If you're currently using HashNuke/heroku-buildpack-elixir, migration is straightforward. The config file name and most options are identical.
heroku buildpacks:set https://github.com/heroku-johnny/buildpack-elixir
git push heroku mainThat's it for most apps. Read on if you hit any of the breaking changes below.
| Change | Action required |
|---|---|
erlang_version and elixir_version are now required |
Add both to your elixir_buildpack.config if missing |
pre_compile and post_compile are removed |
Rename to hook_pre_compile / hook_post_compile (they were already deprecated in the old buildpack) |
config_vars_to_export is not supported |
Remove it; config vars from heroku config are already available during build |
If you're also upgrading from heroku-22 or heroku-24 to heroku-26, update your OTP and Elixir versions — heroku-26 requires OTP 26.0+ and Elixir 1.15+:
# elixir_buildpack.config
erlang_version=29.1.1
elixir_version=1.20.4Check available OTP versions for heroku-26: https://builds.hex.pm/builds/otp/ubuntu-26.04/builds.txt
- Fork the repository
- Create a feature branch:
git checkout -b feat/your-change - Make your changes
- Run the test suite:
test/bats/bin/bats test/unit/ - Run the linter:
shellcheck bin/detect bin/compile bin/release bin/test bin/test-compile lib/*.sh - Open a pull request with a conventional commit title (e.g.
feat: add support for X)
The test suite uses bats-core (included as a git submodule). Run tests for a specific stack:
STACK=heroku-22 test/bats/bin/bats test/unit/
STACK=heroku-24 test/bats/bin/bats test/unit/
STACK=heroku-26 test/bats/bin/bats test/unit/