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#

AttributeTypeRequiredDefaultDescription
manifeststringnomix.exsPackage-relative Mix project manifest used to select the active graph
lockfilestringnomix.lockPackage-relative authoritative lockfile
resolver_inputslist<string>nosrcsPackage-relative text globs supplied to the resolver
graph_filestringnoChecked-in JavaScript Object Notation snapshot with exact manifest, lockfile, Mix environment, and resolver input bindings
vendor_dirstringnodepsPackage-relative directory containing fetched dependency source trees
path_dependenciesmap<string, string>no{}Active path dependency application names mapped to first-party Once targets
mix_envstringnoprodMix environment used to evaluate dependency declarations
dependency_mix_envstringnoprodFallback Mix environment used to compile a dependency when Mix does not report one
configlist<string>no[]Root configuration inputs available while compiling dependencies
config_entrystringnoemptyRoot configuration entry loaded before dependency compilation; it must match an expanded config input
config_targetstringnohostRoot Mix target used while reading config_entry
rootslist<string>no[]Optional application or Hex package names exposed as direct roots
target_prefixstringnomixPrefix for generated package target names
_mix_resolvedboolresolver-ownedfalseMarks a graph expanded from the lockfile
_mix_locked_rootslist<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#

EdgeAcceptsDescription
depselixir_appDirect 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#

CapabilityOutput groups
buildnone

Example#

toml
[[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:

toml
[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.