# nypm: one package manager API for npm, pnpm, yarn, bun and deno

> nypm is a TypeScript library and CLI that hides the differences between Node.js package managers behind a single set of functions and one command, detecting which manager a project uses from package.json and its lockfile. It is small, MIT licensed and released on a monthly cadence, but it deliberately hands argument construction back to the caller.

**unjs/nypm** — 🌈 Unified Package Manager for Node.js (npm, pnpm, yarn), Bun, Deno, Nub, Aube.

- Repository: https://github.com/unjs/nypm
- Stars: 711 · Forks: 40
- Language: TypeScript
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/unjs-nypm

## A thin layer that delegates every command

nypm is a small TypeScript package that gives one interface to several package managers. The documentation lists the supported set: npm, yarn, pnpm, bun, deno, aube, nub and upm. The project describes itself as a unified package manager for Node.js covering npm, pnpm and yarn, plus Bun and Deno, and the repository description also names Nub and Aube.

The important thing about the design is what nypm does not do. It does not implement a package manager. It detects which one a project uses, builds the right command line, and runs it. The runtime dependencies are tiny and tell the story: citty for the command line interface, pathe for cross-platform path handling and tinyexec for process execution. There is no resolver, no lockfile parser and no tarball handling in the dependency list.

The API is a set of named operations, each with an options object. addDependency and addDevDependency add to a project, removeDependency removes, ensureDependencyInstalled checks and installs if needed, installDependencies installs the project dependencies and dedupeDependencies deduplicates them. runScript runs a script defined in package.json, and dlx downloads and executes a package with the package manager.

Alongside those, there is a parallel set of functions whose only job is to produce a command string: installDependenciesCommand, addDependencyCommand, runScriptCommand and dlxCommand. They take a package manager identifier and options such as dev, global, workspace, yarnBerry, short, args and packages, and return the command. This split is the core design decision of the library, and everything else follows from it.

## Detection prefers package.json over the lockfile

detectPackageManager takes a working directory and options, and works out which package manager a project uses by checking sources in a defined order, in the directory and above it.

First is the packageManager field from package.json, the field that also records a version pin. Second is devEngines.packageManager from package.json, the newer npm configuration field for the same purpose. Third, and only if both fields are absent, are known lock files and other files consulted.

That ordering has a direct consequence for anyone building on the library. If a project carries a packageManager field that disagrees with the lockfile on disk, nypm believes the field. A repository that pins pnpm in package.json but has a yarn.lock lying around will get pnpm commands. That is the right default in most cases, since the field is the declared intent, but it means a project with a stale or copy-pasted field will be driven the wrong way, and the library offers no documented override flag in the detection options.

Walking upwards through parent directories is the other detail worth knowing. Detection is not limited to the exact directory given, so running a tool in a subdirectory of a project finds the project root's package.json. That is convenient for scripts that operate on a nested folder, and it also means the closest package.json with a packageManager field wins, walking up.

## The CLI wraps install, add and remove

The command line interface is deliberately thin. Installing the project's dependencies is:

```bash
npx nypm i
```

Adding a dependency:

```bash
npx nypm add defu
```

Removing one:

```bash
npx nypm remove defu
```

The package manifest confirms how this maps to a binary. The bin entry points at the built CLI module, the files array ships only the dist directory, the package is marked as an ES module with sideEffects false, and the module and types fields point at the built index files with a single root export.

That export surface is worth noting. The public API is one entry point, so anything the library offers has to be reachable from the root export, and the type definitions are shipped alongside the JavaScript so consumers get types without a separate package.

The runtime requirement is stated in the manifest as Node 18 or newer, and the package declares its own package manager as pnpm 11.28.6. The project dogfoods what it builds, in the same way it detects others, which is a reasonable sanity check on the detection logic.

## Reading the API from a script or an agent

The library is consumed as a normal import, either statically or dynamically:

```js
// ESM import
import { addDependency } from "nypm";

// or dynamic import
const { addDependency } = await import("nypm");
```

The documentation shows the install step for adding nypm itself into a project, with a comment noting the auto-detection:

```bash
# ✨ Auto-detect
npx nypm install nypm
```

The dynamic import form is the one to pay attention to in agent and server contexts, where you may want to load the library only when a package operation is actually needed rather than at startup, and where the working directory is known only at call time.

The build-and-command functions let a tool show the user what will run before running it. addDependencyCommand returns the string for adding a package, with options for a dev dependency, a global install, a workspace install, yarnBerry mode and the short flag, and dlxCommand returns the string for a one-off execution with args, short and packages options. For a tool that installs things on a user's machine, being able to display the exact command and let the user approve it is worth more than a slightly shorter API.

## Corepack, dedupe and the case of bun and deno

Two behaviours separate nypm from a plain command wrapper, and one of them is a caveat.

The first is corepack integration for pnpm and yarn. Since corepack is how Node.js ships a project-selected package manager version, delegating to it means the version the project asked for is the version that runs, rather than whatever happens to be on the PATH. For a tool that installs dependencies into arbitrary projects, that difference decides whether the install succeeds or produces a different tree.

The second is deduplication, and the note attached to it is explicit: for bun and deno, dedupeDependencies removes the lockfile and reinstalls all dependencies. That is a blunt instrument. There is no incremental dedupe for those two managers, and the effect of the operation is a full reinstall with the lockfile discarded, which means the resolved versions can change.

For a library used inside a tool that touches a user's project, that is a destructive default to be aware of. Calling dedupeDependencies on a bun or deno project will not merely tidy the dependency tree, it will delete the lockfile and resolve again, and the documentation does not describe a way to opt out. The same caution applies to any function that writes to the project.

## Development setup and the shape of the repository

The contribution path is short. The documentation says to clone the repository, enable corepack with corepack enable, install dependencies with pnpm install, and run the interactive tests with pnpm dev. It also asks contributors to play the Nyan Cat in the background, marked as really important.

The manifest scripts show the rest of the toolchain. The build runs automd and obuild, so the README badges and generated sections are produced as part of the build. The test script runs lint, then a type check, then the vitest run with coverage, and lint is oxlint with oxfmt checking the src and test directories. The release script runs the tests and the build, then changelogen with the release and push flags, then publish. The repository root matches: a vitest.config.ts, an oxlintrc.json and an oxfmtrc.json, a build.config.ts, a tsconfig.json, a pnpm-workspace.yaml and a pnpm-lock.yaml.

The tooling is current rather than conservative, which is visible in the dependency versions and in the fact that the type check is a separate tsc --noEmit step rather than a tsc build. The coverage badge is wired to codecov, and the manifest declares the type-check and unit-test steps separately, so a contributor gets both a type failure and a test failure as distinct signals.

## What nypm does not solve, and what to use instead

The honest limitation is that nypm inherits every constraint of the package managers it drives, and adds none of the features they have. It does not do workspaces across repositories, it does not manage versions of the managers themselves, it does not resolve peer dependency conflicts, and it does not give you a lockfile it can rewrite. Every one of those is still the job of npm, pnpm, yarn, bun or deno.

The bun and deno dedupe behaviour described earlier is the sharpest example of that inheritance. A library that wraps eight package managers has to accept that it can only offer the common denominator, and where one manager lacks an operation, the fallback is destructive.

There are two established alternatives, and they differ in approach. The first is to shell out directly, which is what most tools do: detect the manager yourself, build the command string, and spawn it. That is a few dozen lines, and it gives you full control over exactly which flags are passed, which is what you want if you need a specific option nypm does not expose. The second is corepack, which is not a wrapper but a shim: it selects the package manager version from the packageManager field and then hands the rest of the command line to that manager untouched. Corepack solves the version selection problem, which is the part that is genuinely hard to get right, and leaves everything else to the native tool.

nypm earns its place in the gap between those two. It is for the case where you want detection, a uniform API and a CLI, and you would rather not maintain the argument mapping yourself. The projects listed in the documentation as its inspirations, including yarnpm, lmify, ni, install-pkg, dum and corepack, show how crowded that space has become, and nypm's contribution is the programmatic API rather than the shell wrapper.

## Conclusion

Adopt nypm when you are writing a tool, scaffolder or agent that has to install dependencies into whatever project it lands in, and you want one API instead of branching on the package manager. Do not adopt it to replace a package manager in your own workflow, since each command it issues is delegated to the real manager, and do not expect it to reconcile lockfiles, since deduplication for bun and deno means removing the lockfile and reinstalling everything. Before you build on it, check that the projectManager field or devEngines.packageManager entry in your target package.json is what you want nypm to trust, since that field takes priority over the lockfiles nypm falls back on, and confirm that the managers you must support are installed on the machine running your tool.

## FAQ

### What is nypm?

nypm is a TypeScript library and command line tool that provides a unified interface to npm, yarn, pnpm, bun, deno, aube, nub and upm. It ships as the npm package nypm under the MIT licence, with a version requirement of Node 18 or newer.

### How do I install a dependency with nypm?

From the command line you run npx nypm add defu, and npx nypm i installs the project dependencies. From code you import addDependency from nypm, either statically or with a dynamic import, and call it with the package name and an options object.

### How does nypm detect which package manager to use?

detectPackageManager checks the packageManager field in package.json first, then the devEngines.packageManager field, and only then falls back to known lock files and other files, searching the given directory and the directories above it.

### What happens when nypm deduplicates dependencies for bun or deno?

For bun and deno the deduplication removes the lockfile and reinstalls all dependencies, rather than doing an incremental dedupe. The documentation notes this behaviour, and it means resolved versions can change after the call.

### Can nypm give me the command without running it?

Yes. The library exposes installDependenciesCommand, addDependencyCommand, runScriptCommand and dlxCommand, which return the command string for a given package manager with options such as dev, global, workspace, yarnBerry, short, args and packages.

## Sources

- [Issues](https://github.com/unjs/nypm/issues)
- [License: MIT](https://github.com/unjs/nypm/blob/main/LICENSE)
- [README](https://github.com/unjs/nypm/blob/main/README.md)
- [Releases](https://github.com/unjs/nypm/releases)
- [unjs/nypm on GitHub](https://github.com/unjs/nypm)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/unjs-nypm
