Reference
Sharp edges
Last updated October 22, 2026
The behaviors that surprise people, collected in one place. Every one of these is also called out in context on its own page.
authors= GitHub usernames = scope co-ownership. Append-only, and usernames are not verified to exist — a typo silently grants a nonexistent account. (Publishing)- Versions are immutable. There is no unpublish from the CLI — delisting is registry moderation, and existing lockfiles keep working. (Publishing)
embr installwipes and rebuilds the packages-out folders on every full install. Don't keep hand-written files in them — the rebuild deletes them, and the fast path cannot see them. (embr install)- Bare dependencies go to Ember's registry unless
[indices] defaultsays otherwise. (embr index) - Workspace dependency
versiondoes nothing locally — it only shapes the published requirement. (Workspaces) cargo installusers still needembr self installfor tool shims. (Installing Ember)- The packed ember.toml is regenerated on publish — comments dropped, workspace dependencies rewritten. (embr publish)
- A no-op
installis ~10 ms — except roughly once per 5 minutes, when it spends ~0.7 s re-checking the indices. That is the price of^requirements staying live. (embr install) - New releases of
^dependencies appear at most 5 minutes late unless you pass--refresh. (embr install) - The first install after upgrading to embr 0.3.0 re-clones each index
once — the cache key scheme changed, and
embr cache cleanremoves the orphaned old clones. (embr cache) - Archives are cached on the assumption that published versions are
immutable. If a registry ever mutates one,
--refreshorembr cache cleanis the way out. (embr cache) - Override path segments are aliases as each package spelled them, and
they are case-sensitive — for wally packages that usually means
"Comm.Signal", not"comm.signal". Ember warns when a path matches nothing. (Overrides) - An override redirects one edge, not the whole install. If another dependency still asks for the original package, both the original and the replacement end up installed, on purpose. (Overrides)
embx name@versionagainst a pinned alias is an error, not an override. Drop the version to run the pin, or use the fullowner/repoform to run something else. (embx)embr cache cleanleaves the tool store alone. Tool and embx downloads are cleared byembr tool cache cleaninstead. (embr cache)- embx executes code fetched from GitHub by name — the same trust
decision as installing a dependency. Prefer
@versionpins in scripts and CI. (embx) - Only declared dependencies get a top-level link. A transitive
package is installed, but reachable only by the package that asked for
it; require it yourself by adding it to
[dependencies]. (Dependencies & installing) - Environment roots are self-contained, so a package needed by both a shared and a server dependency installs twice — possibly at different versions, because conflicts are judged per root. (Dependencies & installing)
ember.lockversion 2 is breaking. Older embr can't read it, and--lockedrefuses a v1 lock; run one plainembr installto migrate. (Dependencies & installing)- A patch that cannot apply is a hard error, never a silent skip. A
[patches]key whose package left the graph, resolved to a different version, or covers only some environment roots stops the install — an unapplied patch could be someone's security fix. (embr patch) - Patch keys pin an exact version, so a
^dependency picking up a new release fails the install until the patch is re-done against it or removed — your fix is never silently dropped. (embr patch) - Only six scripts can drop the
run.build,test,start,serve,devandfmt/formatare subcommands, and so is a name that starts with one of them and a colon, such asbuild:prod.embr lintis not a command even whenlintis in[scripts], and no script can shadow a real Ember command. (embr run) prepublishruns on--dry-runtoo, because a dry run exists to show the archive a real publish would produce — and the hook is what builds it. (Lifecycle hooks)- In a workspace, each manifest's hooks bracket only its own portion
and run in its own directory, so a root
postinstallfires once, after every member is installed. (Lifecycle hooks) - A list script gives each command a pty on macOS/Linux, so stdout and stderr arrive merged — a terminal has one stream. Redirecting Ember's output switches the whole thing back to pipes, which separates them again and drops colour. (embr run)
- A failing command in a list does not stop the others. They all run to their own end, and Ember exits with the first non-zero code once they have finished. (embr run)
- A
pre/postentry is only a hook if something answers to the rest of the name.preludeis an ordinary script, and so is aprebuildin a manifest with nobuild. (Lifecycle hooks) - Tool assets compressed with zstd, bzip2, 7z or rar are an error, not an install. Ember names the format instead of writing the archive to the binary's path. (embr tool)