Dialyxir for Elixir: Mix Tasks, PLT Caching, and CI Warnings
Mix tasks to simplify use of Dialyzer in Elixir projects.
At a glance
- What is it?
- Dialyxir adds Mix tasks for configuring, building, and running Dialyzer from an Elixir project. It saves repeated analysis in PLT files, supports CI-oriented warning formats, but introduces build artifacts whose validity depends on Erlang, Elixir, and dependency versions.
- Who is it for?
- Dialyxir fits Elixir maintainers who want Dialyzer integrated into Mix and CI. It is a poor fit for developers who need analysis unrelated to BEAM projects or cannot manage version-sensitive PLT caches.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 31 days ago.
- What is it written in?
- Mainly Elixir, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Dialyxir's Place in an Elixir Project
Dialyxir addresses a specific gap around Dialyzer: it exposes Dialyzer through Mix tasks, manages the PLT files that cache analysis, and prepares the Elixir project for analysis. It is intended for Elixir developers who want static type analysis without assembling the underlying `:dialyzer` workflow for every project. Dialyzer itself analyzes BEAM bytecode and can report problems such as type mismatches. Its results can improve when the project supplies typespecs, although specs are not required for Dialyzer to be useful.
The practical distinction is project integration. A developer can invoke `mix dialyzer` from a Mix project, after which Dialyxir can compile the project, determine whether its PLT files need updating, build or copy the required files, and run the analysis. Without this layer, the developer would need to handle more of the toolchain and cache management directly. The documentation does not present Dialyxir as a separate type checker or as a replacement for specs. It is the Mix-facing control surface around Dialyzer.
This makes the tool most relevant to teams with an existing Elixir build process and enough dependency activity for repeated analysis to matter. A small local experiment can also use it, but the PLT lifecycle remains important even when only one developer invokes the task.
How Dialyxir Builds and Refreshes Its PLT Files
A Persistent Lookup Table, or PLT, stores the result of analyzing OTP applications, Elixir libraries, dependencies, and the project environment. The README specifically warns against rebuilding this analysis on every invocation. Dialyxir separates the cached data into three broad files by default.
The core Erlang PLT is stored under `$MIX_HOME` and includes the OTP version in its name. The core Elixir PLT also includes the Elixir version. The project PLT lives under `_build/$MIX_ENV` and carries the OTP version, Elixir version, dependencies, and Mix environment in its filename. When Dialyxir first runs with a particular Erlang and Elixir combination, the documentation states that the core files are copied into the project area as needed.
By default, modules in the project PLT are checked against dependencies so Dialyxir can determine whether it is stale. That check is part of keeping cached type information aligned with the code being analyzed. The `--no-check` option skips this quick validity check, while `--plt` builds the required PLT files and exits without completing the normal analysis path.
The cache is useful, but it introduces an operational constraint. A PLT should be rebuilt after adding a new Erlang or Elixir version. Dependency changes can also invalidate project information because the default check compares project modules with dependencies. The README does not promise perfect invalidation for every possible environment change, so CI cache keys must account for the runtime versions and dependency state rather than treating the `.plt` file as permanently valid.
Adding Dialyxir and Running the First Analysis
Dialyxir is published on `hex.pm`. Add it as a development and test dependency with `runtime: false`, then fetch and compile the dependency from the Mix project directory.
defp deps do
[
{:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false},
]
endThis keeps Dialyxir out of production dependencies and marks it as a development-time tool. Fetch and compile it with the documented Mix command:
mix do deps.get, deps.compileThe expected result is that the dependency is resolved from Hex and compiled as part of the project's development setup. The README does not prescribe a separate global installation command.
Run the first analysis from the root of the Mix project:
mix dialyzerAccording to the README, Dialyxir will create or update a PLT if required and automatically compile the project. The initial invocation can therefore do more than inspect existing warnings: it may pay the analysis cost for core libraries and project dependencies. A first-time user should budget for a slower run and retain the generated files so later invocations can reuse them.
Dialyxir Warning Formats and Analysis Controls
The default `--format dialyxir` output is described as a readable, formatted representation. Dialyxir can print the same warnings in several other formats because command output, ignore files, and GitHub Actions do not consume identical formats. `--format` may be supplied multiple times to print warnings in more than one representation.
For compact suppression data, `--format short` produces warnings in an Elixir term format suitable for an ignore file. `--format dialyzer` retains Dialyzer's original output and uses simple string matching for that workflow. The repository includes `.dialyzer_ignore.exs`, while the documented `ignore_file` and `ignore_file_strict` formats emit `{file, warning_type}` or `{file, warning_description}` entries. The distinction matters because a broad warning type and a specific warning description do not carry the same suppression scope.
For GitHub Actions, `--format github` emits the format expected by GitHub Actions messages. `--list-unused-filters` lists ignore filters that are no longer used and are described as useful for CI cleanup. The README warns not to combine that option with `mix do`.
Dialyxir also supports `--ignore-exit-status` for display-only warning output, `--no-compile` when compilation should not occur even if considered necessary, and `--quiet` or `--quiet-with-result` to reduce informational output. Warning flags are forwarded to `:dialyzer`, so an option such as the following reaches the underlying analysis:
mix dialyzer --unmatched_returnsWarning explanations have a separate task. The following command looks up one warning category:
mix dialyzer.explain unmatched_returnRunning `mix dialyzer.explain` without arguments lists all known warnings. This separation makes the task useful during code review because the warning and its documented explanation do not need to come from the same output format.
CI Caching and the Erlang and Elixir Version Boundary
The README identifies PLT construction as a meaningful CI cost, particularly when a project has many dependencies. It recommends caching the project-level PLT and describes caching the core Erlang and Elixir PLT as optional. The central boundary is runtime compatibility: the README states that the PLT must be rebuilt whenever a new Erlang or Elixir version is added.
A project can move generated PLTs under `priv` by configuring `:plt_file`, `:plt_local_path`, or `:plt_core_path`. This example stores the project PLT in `priv/plts` and suppresses the local-use deprecation warning around `:plt_file`:
def project do
[
...
dialyzer: [
plt_file: {:no_warn, "priv/plts/project.plt"}
]
]
endGenerated PLT files and hash files can then be excluded from version control:
/priv/plts/*.plt
/priv/plts/*.plt.hashThat repository placement does not make the cache safe to share unconditionally. The CI cache must distinguish Erlang versions, Elixir versions, dependencies, and other inputs that affect project analysis. Otherwise, a restored file may represent code compiled against a different environment. The README provides example configurations for CircleCI, GitHub Actions, and GitLab CI, but it does not claim that Dialyxir itself repairs or validates a CI cache key.
CI adoption also needs a policy for exit status. By default, Dialyzer warnings can halt the VM and return a nonzero status. `--ignore-exit-status` is available when the pipeline should display warnings without stopping at the analysis task, but the README does not prescribe whether a team should enforce warnings as failures.
Dialyxir Versus Direct Dialyzer Use
The closest alternative is operating Erlang's Dialyzer directly against the project's BEAM output. Dialyxir itself points readers to the Erlang Dialyzer documentation and passes warning flags through to `:dialyzer`, so the analysis engine is not a competing checker with different findings. The difference is orchestration.
Direct Dialyzer use leaves the developer responsible for preparing the required build output, selecting or maintaining PLT locations, and managing invocation details. Dialyxir packages those concerns into Mix tasks, checks whether the project PLT needs an update, compiles the project when needed, formats results for local use or CI, and provides `mix dialyzer.explain` for warning lookup. It also supports Elixir-specific ignore-file output and CI-oriented formats.
That convenience carries a dependency on Mix and Dialyxir's configuration model. It is not suitable for a non-Elixir codebase that merely has a similarly named task, nor does it remove Dialyzer's PLT invalidation constraints. A team needing exact direct control over `:dialyzer` arguments, custom analysis locations, or a workflow outside Mix may prefer the underlying Dialyzer interface. A team that wants repeated analysis to behave as one documented project command will find Dialyxir's integration more direct.
Maintenance should also be considered. The repository is not archived, the last push was on 2026-09-21, and release `1.4.8` was published on 2026-09-05. That indicates recent maintenance activity, but it does not remove upgrade work: changing Erlang or Elixir can require PLT rebuilding, and dependency changes can affect project analysis. The project uses the `Apache-2.0` license. Its notice and license files should be reviewed for redistribution, notice, and attribution obligations rather than treating the license label as operational guidance.
Editorial conclusion
Dialyxir fits Elixir maintainers who want Dialyzer integrated into Mix and CI. It is a poor fit for developers who need analysis unrelated to BEAM projects or cannot manage version-sensitive PLT caches. Before adoption, verify the first analysis time for your dependency graph, confirm that CI restores and invalidates `priv/plts` correctly for each Erlang and Elixir version, then review whether the default warning formats and ignore files match your review process.
Frequently asked questions
How do I install Dialyxir in an Elixir project?
Add `{:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false}` to `deps`, then run `mix do deps.get, deps.compile`. The README says Dialyxir is available through `hex.pm`.
What does the first `mix dialyzer` run do?
It compiles the project when needed and creates or updates the required PLT files. Those PLT files cache analysis for subsequent runs.
When should Dialyxir rebuild a PLT in CI?
The README specifically says to rebuild it whenever the project adds a new Erlang or Elixir version. Dependency changes can also make project information stale, and Dialyxir checks project modules against dependencies by default.
How can Dialyxir output warnings for GitHub Actions?
Pass `--format github` to `mix dialyzer`. The documented value selects the GitHub Actions message format.
Can Dialyxir continue after Dialyzer returns warnings?
Yes. `--ignore-exit-status` displays warnings without halting the VM or returning an exit status code. The README does not prescribe when a CI pipeline should use this option.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/jeremyjh-dialyxir)Was this useful?