Documentation menu

The manifest

[overrides]

Last updated August 24, 2026

[overrides] replaces a dependency of a dependency — when a package you depend on pulls a version you don't want, or you would rather it used your fork:

[dependencies]
Comm = { name = "sleitnick/comm", version = "^1", index = "wally" }
Signal = { name = "sleitnick/signal", version = "=2.0.0", index = "wally" }

[overrides]
"Comm.Signal" = "Signal"

That reads: wherever Comm asks for its Signal, use mine instead — including when yours is a fork under a completely different package name. (Coming from pesde? Same idea; Ember writes . where pesde writes >.)

Keys are alias paths#

Dot-separated, at least two segments:

  • The first segment is an alias under your [dependencies].
  • Each further segment is the alias the previous package's own manifest declares for its dependency — case-sensitive, spelled exactly as that package wrote it. Wally packages usually capitalize: Promise, not promise.
  • Segments are aliases, never package names.
  • One key can cover several paths, separated by commas: "Foo.Bar, Baz.Bar" = ….
  • Aliases containing dots or whitespace cannot be addressed.

Values#

Both shapes work, alias shorthand and full specifier:

[overrides]
# Alias shorthand: one of your own [dependencies] entries.
"Comm.Signal" = "Signal"

# Full specifiers: the same shapes a [dependencies] value takes.
"Comm.Promise" = { name = "evaera/promise", version = "^4", index = "wally" }
"Comm.Util"    = { workspace = "acme/util" }
  • An alias string — the alias of one of your own [dependencies] entries. The replacement can be a fork under a completely different package name; the alias is what matters.
  • A full specifier — registry ({ name = …, version = …, index = … }) or workspace ({ workspace = … }), exactly like [dependencies] values. An index key resolves against your [indices], not the overridden package's.

What an override actually changes#

Ember installs one version per package name per environment root, and an override redirects one edge. Dependents that ask for the original package by name keep it, so the original and the replacement then coexist in that root, each linked where it was asked for.

A package's dependency edges are considered once, on first discovery (your [dependencies] aliases seed in alphabetical order). A deeper path like "A.B.C" has to spell that first route; if the package at A.B was first reached some other way, Ember warns and names the route that was walked. Segments below an overridden edge address the replacement's dependencies.

Overrides don't suspend version checking — if an override's requirement conflicts with what another dependent demands of the same package, install fails with the normal dependency conflict error.

The lockfile records redirected edges, so --locked reproduces them exactly. Only the installing project's [overrides] applies — a dependency's own table never reshapes your install (published packages don't carry one; publish strips the table), and in a workspace a member's own table applies when that member installs.

Diagnostics#

Checked at install, before any network traffic. Errors:

  • [overrides] key '<key>' must be a dot-separated path like 'parent.child' (commas separate multiple paths)
  • Override '<path>' points at '<alias>', which is not under [dependencies]
  • Two [overrides] keys both cover the path '<path>'
  • an unknown index key in a value fails like any dependency's would

Warnings, which install continues past:

  • warning: override '<path>' matched no dependency; check the alias path
  • warning: override '<path>' could not apply: that package's dependencies were walked via '<other path>' first; address the edge there