Skip to content

elixir-volt/npm_ex

Repository files navigation

NPM

Hex.pm CI

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 install step 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

  1. Read package.json dependencies, dev dependencies, optional dependencies, and overrides.
  2. Resolve the full dependency tree using hex_solver and npm_semver.
  3. Fetch registry packuments and tarballs with integrity verification.
  4. Store package contents in the global cache.
  5. Link packages into node_modules/ and write npm.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, or prepare are 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_deps allowlist 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_MIRROR
  • NPM_EX_CACHE_DIR, NPM_INSTALL_DIR
  • NPM_EX_BLOCK_EXOTIC_SUBDEPS, NPM_EX_EXOTIC_DEPS
  • NPM_EX_ALLOWED_REGISTRIES, NPM_EX_ALLOW_REGISTRY_REDIRECTS
  • NPM_EX_PACKAGE_AGE_WARNING_DAYS, NPM_EX_VERSION_AGE_WARNING_DAYS
  • NPM_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

License

MIT © 2026 Danila Poyarkov

About

npm package manager for Elixir

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages