mix_dependencies
Locked Mix dependency graph consumed by Elixir targets.
Description#
During graph loading, Once reads a checked-in graph snapshot or asks Mix to
evaluate the dependencies active for the configured environment. Once reads package identity from the committed
mix.lock and does not run a second version solver. Every active locked Hex or
Git dependency becomes a synthetic mix_package target with its own source
inputs, build action, and dependency edges.
The lockfile is authoritative. Graph loading fails when an active Mix
dependency has no lock entry, when the manifest or lockfile is not included in
resolver_inputs, or when a selected source is outside the Once package. When
resolver_inputs is empty or omitted, srcs supplies those files instead.
Resolution does not fetch sources and never writes mix.lock.
Dependency sources must already exist under vendor_dir, normally deps.
This separates network and registry access from build execution. Package build
actions enable Hex offline mode and use the locked source tree as declared
inputs. Live graph loading uses the vendored source tree and committed lockfile
without requiring a separately installed Hex archive.
The selected mix_env controls which dependencies are present in the root
graph. Each generated package compiles with the environment reported by Mix
for that dependency. dependency_mix_env supplies the fallback when Mix does
not report one. This matches native Mix behavior, where a test graph may
contain packages that compile in their own production environment.
When dependency compilation reads root application configuration, declare
config_entry and include that file plus every transitively imported
configuration file in config. Once reads the root configuration with
mix_env and config_target, then restores the dependency environment before
running its compiler pipeline. This preserves the distinction between the
root graph environment and each dependency's compilation environment.
Use target_prefix when one package declares dependency graphs for more than
one root environment. Separate development, test, and production dependency
targets keep their configuration and action identities independent.
The aggregate target depends only on the direct roots selected by Mix. The
synthetic targets carry transitive edges, so Once still sees and schedules the
complete graph. An optional roots list can expose a narrower set by Mix
application name or Hex package name.
Attributes#
| Attribute | Type | Required | Default | Description |
|---|---|---|---|---|
manifest | string | no | mix.exs | Package-relative Mix project manifest used to select the active graph |
lockfile | string | no | mix.lock | Package-relative authoritative lockfile |
resolver_inputs | list<string> | no | srcs | Package-relative text globs supplied to the resolver |
graph_file | string | no | Checked-in JavaScript Object Notation snapshot with exact manifest, lockfile, Mix environment, and resolver input bindings | |
vendor_dir | string | no | deps | Package-relative directory containing fetched dependency source trees |
path_dependencies | map<string, string> | no | {} | Active path dependency application names mapped to first-party Once targets |
mix_env | string | no | prod | Mix environment used to evaluate dependency declarations |
dependency_mix_env | string | no | prod | Fallback Mix environment used to compile a dependency when Mix does not report one |
config | list<string> | no | [] | Root configuration inputs available while compiling dependencies |
config_entry | string | no | empty | Root configuration entry loaded before dependency compilation; it must match an expanded config input |
config_target | string | no | host | Root Mix target used while reading config_entry |
roots | list<string> | no | [] | Optional application or Hex package names exposed as direct roots |
target_prefix | string | no | mix | Prefix for generated package target names |
_mix_resolved | bool | resolver-owned | false | Marks a graph expanded from the lockfile |
_mix_locked_roots | list<string> | resolver-owned | [] | Records generated root target names |
The underscore-prefixed attributes are produced by the resolver and should not
be set in once.toml.
Dependency Edges#
| Edge | Accepts | Description |
|---|---|---|
deps | elixir_app | Direct locked package roots emitted by the resolver |
Transitive package relationships are ordinary deps edges between generated
mix_package targets.
Providers#
The target emits mix_dependency_set and elixir_app. The elixir_app
provider aggregates every reachable package so first-party Elixir targets can
consume one dependency edge.
Capabilities#
| Capability | Output groups |
|---|---|
build | none |
Example#
[[target]]
name = "mix_dependencies"
kind = "mix_dependencies"
srcs = ["mix.exs", "mix.lock", "mix-dependencies.json"]
[target.attrs]
manifest = "mix.exs"
lockfile = "mix.lock"
graph_file = "mix-dependencies.json"
resolver_inputs = ["mix.exs", "mix.lock", "mix-dependencies.json"]
vendor_dir = "deps"
mix_env = "test"
target_prefix = "mix-test"
config = ["config/**/*.exs"]
config_entry = "config/config.exs"
[[target]]
name = "greeting"
kind = "elixir_library"
srcs = ["lib/**/*.ex"]
deps = ["./mix_dependencies"]
The snapshot contains the exact manifest and lockfile text, the selected
mix_env, a once_inputs map, the normalized lock object, and a
dependencies array. once_inputs contains every exact resolver input except
the snapshot itself. Include each path dependency manifest in
resolver_inputs. Graph loading rejects any binding that differs from the
target.
Each dependency records app, dependencies, destination, manager,
top_level, path_dependency, and custom_compile. Check in this file to keep
ordinary graph queries independent of the Elixir toolchain. Omit it while
refreshing dependencies so Mix evaluates the active graph, then review and
record the normalized result before restoring tool-free queries.
Map every active path dependency to an ordinary first-party target. The mapped
target participates in the imported root and transitive edges instead of being
silently omitted. Once stages mapped projects at their workspace-relative
source roots, so the path expression in mix.exs continues to resolve inside
the isolated build workspace:
[target.attrs.path_dependencies]
local_helper = "./local_helper"
Supported Sources and Build Managers#
Locked Hex and Git entries are supported. A generated package may use Mix or Rebar 3 as its build manager. Make-only packages and dependency declarations that override the compile command fail explicitly.
The live graph reader requires Erlang 27 or newer for its built-in JavaScript Object Notation encoder. Checked-in snapshots do not require Mix or Erlang during graph loading.
Sources#
- Mix dependencies defines the project dependency forms, environment selection, and native graph behavior.
- Hex usage explains repeatable fetching and why the lockfile should be committed.
- Hex package checksums explains the integrity role of package checksums preserved by generated targets.