Dependency management
Ende is a package manager for JSR packages and HTTPS imports,
built into the ende binary. Dependencies are declared in ende.json. This
page covers the day-to-day workflow; the
toolbelt table lists every command.
Quick start
In a project that already declares dependencies in ende.json, install them
with:
ende install
Add a new dependency from JSR:
ende add jsr:@ende/assert
The dependency is recorded in ende.json, and you import it by its bare name:
import { assertEquals } from "@ende/assert";
The dependency toolbelt
Every dependency task has a built-in subcommand. Each links to its full reference:
| Command | What it does |
|---|---|
ende install |
Install the project's dependencies (or a tool, with -g) |
ende add |
Add a dependency to the config file |
ende remove |
Remove a dependency from the config file |
ende outdated |
List dependencies with newer versions |
ende update |
Update dependencies to newer versions |
ende why |
Explain why a package is in your dependency tree |
ende info |
Show a module's full dependency graph and cache details |
ende ci |
Install strictly from the lockfile, for CI |
ende publish |
Publish a package to JSR |
ende uninstall |
Remove a globally installed tool |
ende clean |
Remove the global module cache |
Choosing versions
It is possible to specify a version range for the package you are importing.
This is done using the @ symbol followed by a version range specifier, and
follows the semver versioning scheme. To share a single
version range across workspace members, declare it in the workspace root's
imports.
For example:
@scopename/mypackage # highest version
@scopename/[email protected] # exact version
@scopename/mypackage@16 # highest 16.x version >= 16.0.0
@scopename/mypackage@^16.1.0 # highest 16.x version >= 16.1.0
@scopename/mypackage@~16.1.0 # highest 16.1.x version >= 16.1.0
Here is an overview of all the ways you can specify a version or a range:
| Symbol | Description | Example |
|---|---|---|
1.2.3 |
An exact version. Only this specific version will be used. | 1.2.3 |
^1.2.3 |
Compatible with version 1.2.3. Allows updates that do not change the leftmost non-zero digit. For example, 1.2.4 and 1.3.0 are allowed, but 2.0.0 is not. |
^1.2.3 |
~1.2.3 |
Approximately equivalent to version 1.2.3. Allows updates to the patch version. For example, 1.2.4 is allowed, but 1.3.0 is not. |
~1.2.3 |
>=1.2.3 |
Greater than or equal to version 1.2.3. Any version 1.2.3 or higher is allowed. |
>=1.2.3 |
<=1.2.3 |
Less than or equal to version 1.2.3. Any version 1.2.3 or lower is allowed. |
<=1.2.3 |
>1.2.3 |
Greater than version 1.2.3. Only versions higher than 1.2.3 are allowed. |
>1.2.3 |
<1.2.3 |
Less than version 1.2.3. Only versions lower than 1.2.3 are allowed. |
<1.2.3 |
1.2.x |
Any patch version within the minor version 1.2. For example, 1.2.0, 1.2.1, etc. |
1.2.x |
1.x |
Any minor and patch version within the major version 1. For example, 1.0.0, 1.1.0, 1.2.0, etc. |
1.x |
* |
Any version is allowed. | * |
Inspecting and updating dependencies
See which dependencies have newer versions, then update them:
ende outdated # display what's behind, without changing anything
ende update # update to the latest semver-compatible versions
ende update --latest # ignore semver ranges and go to the newest releases
When you want to know where a package comes from,
ende why prints every dependency path that
leads to it:
ende why jsr:@ende/fmt
ende info shows a module's full dependency
graph, including sizes and cache locations, for your entry point or any
specifier:
ende info main.ts
ende info jsr:@ende/http
Lockfile and reproducible installs
Ende automatically maintains a ende.lock file recording the exact version and
integrity hash of every dependency, and verifies it on subsequent runs. Commit
it. In CI and production, install strictly from the lockfile with
ende ci, which errors if ende.lock is missing
or out of date instead of silently resolving new versions:
ende ci
You can also enforce a frozen lockfile on any command with --frozen-lockfile,
or configure the lockfile's behavior and path in
ende.json. For why this matters and
what to do when the lockfile fights you, see
Supply chain management.
Overriding dependencies
Ende provides mechanisms to override dependencies, enabling developers to use custom or local versions of libraries during development or testing.
Note: If you need to cache and modify dependencies locally for use across
builds, set "vendor": true in ende.json to vendor remote modules.
Overriding local packages
The links field in ende.json points JSR dependencies at local copies. This
allows you to override dependencies with local versions during development
without needing to publish them.
Example:
{
"links": [
"../some-package-or-workspace"
]
}Key points:
- The
linksfield accepts paths to directories containing packages or workspaces. If you reference a single package within a workspace, the entire workspace will be included. - This feature is only respected in the workspace root. Using
linkselsewhere will trigger warnings.
Limitations:
- Git-based dependency overrides are unavailable.
- The
linksfield requires proper configuration in the workspace root.
Overriding HTTPS imports
Ende also allows overriding HTTPS imports through the scopes field in
ende.json. This feature is particularly useful when substituting a remote
dependency with a local patched version for debugging or temporary fixes.
Example:
{
"imports": {
"example/": "https://deno.land/x/example/"
},
"scopes": {
"https://deno.land/x/example/": {
"https://deno.land/x/[email protected]/mod.ts": "./patched/mod.ts"
}
}
}Key points:
- The
scopesfield in the import map allows you to redirect specific imports to alternative paths. - This is commonly used to override remote dependencies with local files for testing or development purposes.
- Scopes apply only to the root of your project. Nested scopes within dependencies are ignored.
Development only dependencies
Sometimes dependencies are only needed during development, for example dependencies of test files or build tools. In Ende, the runtime does not require you to distinguish between development and production dependencies, as the runtime only loads and installs the dependencies that the code being executed actually uses.
However, it can be useful to mark dev dependencies to aid people who are reading
your package. When using ende.json, the convention is to add a // dev
comment after any "dev only" dependency:
{
"imports": {
"@ende/fs": "jsr:@ende/fs@^2026.10.15",
"@ende/testing": "jsr:@ende/testing@^2026.10.15" // dev
}
}To install only what an entrypoint actually imports, for example when building a
production image, use ende install --entrypoint:
ende install --entrypoint main.ts
HTTPS imports
Ende can import modules directly from https: URLs, either inline or mapped in
ende.json. This suits small single-file scripts, but JSR is recommended for
applications: HTTPS imports can drift to different versions across files, aren't
managed by ende add/ende install, and trust the serving host. To pin and
localize them, set "vendor": true in ende.json.
Go deeper
- Publishing packages: publishing to JSR.
- Supply chain management: lockfile discipline, minimum dependency age, and a CI baseline.
- Private repositories:
authenticate remote module hosts with
ENDE_AUTH_TOKENS.