- Elixir 100%
| .github/workflows | ||
| guides | ||
| lib | ||
| priv/security | ||
| test | ||
| .credo.exs | ||
| .dialyzer_ignore.exs | ||
| .formatter.exs | ||
| .gitignore | ||
| .tool-versions | ||
| CHANGELOG.md | ||
| LICENSE | ||
| mix.exs | ||
| mix.lock | ||
| README.md | ||
NPM
npm package management for Elixir — resolve, fetch, cache, and link npm packages from Mix without requiring Node.js for installation.
mix npm.install lodash
mix npm.exec eslint .
npm_ex reads package.json, resolves npm semver with PubGrub, writes npm.lock, and links packages into node_modules/.
Why npm_ex
Elixir projects increasingly need JavaScript packages for assets, formatters, linters, browser libraries, and runtime integrations. npm_ex keeps that workflow inside Mix:
- no
npm installstep required for dependency resolution or linking - reproducible installs through
npm.lock - global package cache in
~/.npm_ex/cache/ - npm registry auth, mirrors, scoped registries, peer/deprecation warnings
- CI-friendly Mix tasks for install, verify, audit, outdated, tree, and exec
Installation
def deps do
[{:npm, "~> 0.7.0"}]
end
mix npm.init
mix npm.install lodash
Common workflows
# Install and maintain dependencies
mix npm.install
mix npm.install lodash@^4.0
mix npm.install eslint --save-dev
mix npm.update
mix npm.remove lodash
# CI / reproducibility
mix npm.install --frozen
mix npm.ci
mix npm.verify
# Inspect dependency state
mix npm.list
mix npm.tree
mix npm.why accepts
mix npm.outdated
# Run scripts and binaries
mix npm.run build
mix npm.exec eslint .
# Registry, cache, and config
mix npm.info express
mix npm.search react
mix npm.cache status
mix npm.config
How installs work
- Read
package.jsondependencies, dev dependencies, optional dependencies, and overrides. - Resolve the full dependency tree using hex_solver and npm_semver.
- Fetch registry packuments and tarballs with integrity verification.
- Store package contents in the global cache.
- Link packages into
node_modules/and writenpm.lock.
npm_ex uses its own npm.lock because it is not npm. package.json remains the shared manifest; npm.lock records npm_ex's resolved dependency graph and security policy.
Supply-chain safety
npm_ex is intentionally conservative around install-time code execution:
- package lifecycle hooks are not executed automatically
- packages declaring
preinstall,install,postinstall, orprepareare installed but reported as warnings - tarball paths are validated before extraction to prevent cache escapes
- transitive git, URL, GitHub shorthand, and
file:dependencies are blocked by default - direct exotic dependencies require an explicit
exotic_depsallowlist entry - registry origins and redirects are policy checked
- newly created packages and freshly published versions can warn during install
This blocks common install-time credential stealers that rely on postinstall hooks reading files like .env and exfiltrating secrets during dependency installation.
Auditing malicious packages
mix npm.audit supports npm vulnerability checks and OSV/OpenSSF malicious-package intelligence:
# npm registry vulnerability audit
mix npm.audit
# Strict online OSV malicious-package gate
mix npm.audit --osv
# Refresh the shared local malicious-package cache for the current lockfile
mix npm.audit --osv --write-cache --policy warn
# Deterministic offline gate using the shared cache or configured DB
mix npm.audit --compromised
--write-cache merges matching OSV advisories into ~/.npm_ex/security/compromised_packages.json by default. mix npm.audit --osv fails closed when OSV cannot be queried; mix npm.audit --compromised is offline and deterministic.
OpenSSF/OSV is the default-compatible open data source. Socket, Snyk, and Phylum provide valuable proprietary intelligence or install-time firewall workflows; they fit best as external scanners/proxies or future optional integrations rather than default npm_ex install dependencies.
Configuration
Most projects only need the defaults. Use mix npm.config to inspect effective settings.
Common environment variables:
NPM_REGISTRY,NPM_TOKEN,NPM_MIRRORNPM_EX_CACHE_DIR,NPM_INSTALL_DIRNPM_EX_BLOCK_EXOTIC_SUBDEPS,NPM_EX_EXOTIC_DEPSNPM_EX_ALLOWED_REGISTRIES,NPM_EX_ALLOW_REGISTRY_REDIRECTSNPM_EX_PACKAGE_AGE_WARNING_DAYS,NPM_EX_VERSION_AGE_WARNING_DAYSNPM_EX_COMPROMISED_DB_PATH,NPM_EX_COMPROMISED_POLICY
Elixir application config is also supported:
config :npm,
registry: "https://registry.npmjs.org",
token: System.get_env("NPM_TOKEN"),
cache_dir: Path.expand("~/.npm_ex"),
block_exotic_subdeps: true,
exotic_deps: [],
allowed_registries: ["https://registry.npmjs.org"],
allow_registry_redirects: false,
package_age_warning_days: 7,
version_age_warning_days: 3,
compromised_db_path: Path.expand("~/.npm_ex/security/compromised_packages.json"),
compromised_policy: :error
API organization
The main public API is NPM. Supporting modules are grouped by domain: NPM.Package.*, NPM.Dependency.*, NPM.Lockfile.*, NPM.Security.*, NPM.Registry.*, NPM.Config.*, NPM.Install.*, NPM.Node.*, NPM.NodeModules.*, and NPM.Diagnostics.*.
See CHANGELOG.md for the 0.7 migration map from older pre-namespace module names.
Documentation
Full guides and API documentation are available on HexDocs:
- Getting Started
- Dependency Workflows
- CI and Reproducibility
- Supply-Chain Safety
- Malicious Package Audits
- Configuration
- CLI and configuration cheatsheets
Part of Elixir Volt
npm resolves, fetches, and links npm packages from Mix — no Node.js required for installation.
It is part of a frontend stack that runs inside the BEAM — builds, JS runtimes, icons, and Vue-to-LiveView compilation as supervised parts of the application instead of external toolchain processes. See the Elixir Volt organization for the rest, and Building Blocks for the Future Web for the thesis, architecture, and roadmap that tie them together.
License
MIT © 2026 Danila Poyarkov