Skip to content

Back to the catalog

upm Launches as a Fast, Tiny Package Manager Written in TypeScript
socket.devarticle

upm Launches as a Fast, Tiny Package Manager Written in TypeScript

Socket covers upm, a new ~250KB TypeScript package manager built by Nuxt/Nitro/UnJS creator Pooya Parsa that uses only Node.js built-ins for fast npm installs and exposes a JavaScript API for embedding in other tools. Its security-relevant defaults include disabling dependency lifecycle install scripts and enforcing a one-day minimum release age before selecting new package versions (both configurable), aimed at mitigating malicious install-script and fresh-release supply-chain attacks; it also lacks hoisting and can read (but has limited compatibility with) npm, pnpm, and bun lockfiles.

TL;DR New tiny npm-compatible package manager (upm) ships with install-scripts disabled by default and a 24-hour release-age cooldown to blunt supply-chain attacks.
Document

What it is

upm, a prerelease TypeScript package manager for the npm registry, ships two on-by-default security behaviors whose exact edge-case mechanics the summary flattens: skipping dependency lifecycle scripts on install, and a one-day minimum release age when selecting new versions. The details below are what an engineer weighing adoption actually needs, because both defaults have failure modes and escape hatches.

How the release-age rule resolves versions

The 24-hour cooldown does not simply block new versions — it changes selection:

  • If latest points to a version younger than the age threshold, upm picks the newest eligible older version instead.
  • If no version in the requested range satisfies the age rule, installation fails.
  • The rule does not replace a version already pinned in upm.lock, and does not override an explicitly requested exact version.

So the protection covers fresh releases entering a dependency tree during resolution; it deliberately steps aside for exact pins and existing lockfile entries. The delay is configurable or can be disabled.

Install-script skipping and its cost

Skipping lifecycle scripts stops the classic malicious-install-script path, but packages that build or download files at install time may break and need extra setup. A downloaded package's command can still be run manually via upx. The default only concerns scripts that would run automatically during installation.

Preconditions / operational limits

Behaviors that constrain whether you can rely on it in a real project:

  • Foreign lockfiles are read-only and restricted. upm can install from package-lock.json, pnpm-lock.yaml, or bun.lock (when no upm.lock exists) without rewriting them — but those lockfiles cannot contain workspaces, patches, or Git/file dependencies, and upm cannot add or remove packages while using them.
  • .npmrc: scoped registries and credentials are honored; proxy and certificate settings are not supported.
  • No audit. npm-based auditing is not wired in because npm cannot parse upm's layout or lockfile — a gap if you rely on npm audit in CI.
  • Prerelease gaps: no update command, no Git/local-directory dependencies, limited peer-dependency handling.
  • No hoisting: each package sees only its declared dependencies, so undeclared-dependency accidents don't resolve.

Caveats

The size/speed comparison is the vendor's own and the article flags it as "a little lopsided": Bun/Deno sizes include their runtimes, and the CI cache-restore figure is an estimate, not a measured full CI job. On warm installs upm ranked fourth (36–125 ms) behind Bun, aube, and Deno; it led cold installs except on Nitro (pnpm faster).

Organisations named here

  • Pooya Parsa

Technologies named here

  • upm
  • npm
  • pnpm
  • Yarn
  • Bun
  • Deno
  • Nub
  • UPX
  • Node.js
  • TypeScript

Techniques named here

  • Malicious install scripts
  • Fresh malicious releases pushed into dependency trees
  • Dependency hoisting