prefers-yarn [![Version][npm-version-image]][npm-version-url] [![Downloads][npm-downloads-image]][npm-downloads-url] [![workflow][action-image]][action-url] [![provenance][provenance-image]][provenance-url]
June 22, 2026 ยท View on GitHub
Detect the package manager (npm, yarn, pnpm, bun) a project prefers, then resolve a runnable command for it.
prefers-yarn

prefers-yarn combines several signals (lockfiles, the packageManager field, npm_config_user_agent, corepack) to detect the package manager a project prefers:
- the invoking process (
npm_config_user_agent/npm_execpath) - modern lockfiles (
pnpm-lock.yaml,yarn.lock,bun.lockb/bun.lock,package-lock.json) - the corepack
packageManagerfield - a Windows-safe PATH probe (
where.exe,.cmdshims)
When the preferred manager is not directly runnable, it routes through corepack or falls back to the npm CLI bundled with the current Node.js install, so CLI authors always get a runnable package manager. Zero dependencies.
Installation
npm install prefers-yarn
Usage
import { detectPackageManager } from 'prefers-yarn'
detectPackageManager()
// => 'npm' | 'yarn' | 'pnpm' | 'bun'
detectPackageManager({ cwd: '/path/to/project' })
// => respects that project's lockfile / packageManager field
Building and running an install command:
import {
resolvePackageManager,
buildInstallCommand,
runCommand
} from 'prefers-yarn'
const pm = resolvePackageManager({ cwd: projectDir })
// => { name: 'pnpm', execPath: '/usr/local/bin/pnpm' }
const { command, args } = buildInstallCommand(pm, ['install', '--silent'])
await runCommand(command, args, { cwd: projectDir, stdio: 'inherit' })
API
detectPackageManager(opts?)
Returns 'npm' | 'yarn' | 'pnpm' | 'bun'. Resolution order:
- Lockfile in
opts.cwd(pnpm-lock.yaml,yarn.lock,bun.lockb/bun.lock,package-lock.json) packageManagerfield in the package.json atopts.cwd(corepack)PREFERRED_PACKAGE_MANAGER/PREFERRED_PM_EXEC_PATHenv overrides- Invoking process env (
npm_config_user_agent,npm_execpath) - pnpm, yarn, or bun found on PATH
- corepack
- The npm CLI bundled with the current Node.js install
'npm'as a last resort
resolvePackageManager(opts?)
Same resolution order, but returns the full
{ name, execPath?, runnerCommand?, runnerArgs? } shape so you can actually
spawn the package manager (e.g. node /path/to/npm-cli.js or
corepack pnpm).
detectPackageManagerFromEnv()
Environment-only detection (user agent, then npm_execpath /
NPM_EXEC_PATH / BUN_INSTALL). Defaults to 'npm'. Useful for "which
package manager launched my CLI?".
getPackageManagerSpec() / getPackageManagerVersion()
Parse the invoking package manager's version from
npm_config_user_agent: 'pnpm@9.9.0' or
{ name: 'pnpm', version: '9.9.0' }, or null when unavailable.
detectPackageManagerFromLockfile(cwd) / detectPackageManagerFromPackageJson(cwd)
The individual project-level heuristics, exported for composing your own
ordering. Both return a name or undefined.
buildInstallCommand(pm, args)
Turns a PackageManagerResolution into a spawnable { command, args },
keeping JS entrypoints under node and executing native/Windows binaries
directly.
buildNpmCliFallback(args)
{ command, args } for the npm CLI bundled with the running Node.js
(node /path/to/npm-cli.js ...args), or undefined if it can't be found.
runCommand(command, args, options?)
Promise-based spawn wrapper that handles Windows .cmd/.bat shells and
ensures the Node.js directory is on PATH. Options: cwd,
stdio ('inherit' | 'ignore' | 'pipe', default 'ignore').
resolveCommandOnPath(command) / canRunCorepack() / buildExecEnv()
Lower-level helpers: Windows-safe executable resolution (prefers .cmd
shims via where.exe, uses which elsewhere), corepack availability, and a
Windows PATH-patched env for spawning.
prefersYarn(cwd?) (default export)
The v1 API: true when a yarn.lock exists in cwd (default
process.cwd()).
Migrating from v1
v1 exported a single function:
const prefersYarn = require('prefers-yarn')
prefersYarn() // boolean
In v2 the same function is still there, as both the default and a named export, but the package now ships ESM + CJS builds, so CJS consumers should destructure:
// CJS
const { prefersYarn } = require('prefers-yarn')
// ESM
import prefersYarn from 'prefers-yarn'
For new code, prefer detectPackageManager(): it answers the broader
question ("which package manager?") instead of just "is it yarn?".
v2 requires Node.js >= 18.
Related projects
License
MIT (c) Cezar Augusto.