Skip to content
Latchkey

Phoenix "mix assets.deploy" esbuild/tailwind not found in CI

Phoenix builds frontend assets with the esbuild and tailwind Hex wrappers, which download a platform binary on first use. In CI, if that install step never ran, mix assets.deploy cannot find the tool.

What this error means

A release build fails at mix assets.deploy with "could not find esbuild executable" / "tailwind executable ... not found", or the download step was skipped.

** (RuntimeError)
** (RuntimeError) esbuild executable not found. Run `mix esbuild.install` to
install esbuild for the target platform.

Common causes

The esbuild/tailwind binary was never installed

The wrappers fetch a binary on demand; if mix esbuild.install/mix tailwind.install did not run (or the download was cached out), the tool is absent.

assets.deploy runs before the tools are provisioned

The release step calls assets.deploy without a prior install, so the pipeline has no bundler.

How to fix it

Install the asset tools before deploy

  1. Run mix esbuild.install and mix tailwind.install --if-missing in a setup step.
  2. Then run mix assets.deploy to bundle and digest.
  3. Re-run the release.
.github/workflows/ci.yml
- run: |
    mix esbuild.install --if-missing
    mix tailwind.install --if-missing
    mix assets.deploy
  env:
    MIX_ENV: prod

Cache the downloaded binaries

Persist the esbuild/tailwind binaries so runs after the first skip the download.

.github/workflows/ci.yml
- uses: actions/cache@v4
  with:
    path: _build/${{ env.MIX_ENV }}/lib/esbuild
    key: esbuild-${{ runner.os }}-${{ hashFiles('**/mix.lock') }}

How to prevent it

  • Install esbuild/tailwind before assets.deploy in release jobs.
  • Cache the downloaded asset binaries between runs.
  • Set MIX_ENV=prod so digested assets go to the right build.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →