bin-links: Package Binary Linker
bin-links is a fundamental JavaScript library within the npm ecosystem, responsible for linking package binaries and man pages. It handles the creation of symbolic links or shims for executable scripts defined in a package's `bin` field, directing them to appropriate locations like `node_modules/.bin` for local installs or global binary directories for global packages. It also manages linking man pages from the `man` field. The current stable version is v6.0.0, released in late 2025. This package generally follows the Node.js release cadence for its engine support, aligning with npm's own requirements. Its key differentiator is being a core, low-level utility maintained by the npm team, providing robust and cross-platform binary linking functionality crucial for package execution and discoverability in Node.js environments.
Common errors
-
Error: EACCES: permission denied, link '...' -> '...'
cause The Node.js process lacks the necessary file system permissions to create symbolic links or shims in the target directory.fixEnsure the user running the Node.js process has write permissions to the destination directory (e.g., `node_modules/.bin` or global `bin` directory). On Unix-like systems, you might need to use `sudo` for global installations, though this is generally discouraged for local `npm install`. -
TypeError: require is not a function
cause Attempting to use `require('bin-links')` in an ES Module context where CommonJS `require` is not natively available or polyfilled.fixRefactor your import statement to use `import binLinks from 'bin-links';` to align with ESM syntax. Ensure your project is configured for ESM (e.g., `"type": "module"` in `package.json`). -
Error: The 'engines' field is not compatible with the current Node.js version.
cause The `bin-links` package specifies a strict Node.js engine range in its `package.json`, and your current Node.js version falls outside this range.fixUpgrade your Node.js runtime to a version that satisfies the `engines.node` requirement specified in `bin-links`'s `package.json` (e.g., `^20.17.0 || >=22.9.0` for v6.0.0). Use a Node Version Manager (NVM) to switch to a compatible version.
Warnings
- breaking Node.js engine requirements have been progressively tightened. Version 6.0.0 requires Node.js `^20.17.0 || >=22.9.0`. Ensure your Node.js environment meets these specifications to avoid compatibility issues.
- breaking With the release of v5.0.0, the Node.js engine requirement was updated to `^18.17.0 || >=20.5.0`. Running on older Node.js versions will lead to failures.
- breaking Version 4.0.0 introduced a significant change where `bin-links` no longer automatically attempts to change file ownership. Operations that previously relied on this automatic ownership alteration may now require manual handling of file permissions.
- gotcha On Windows, `bin-links` creates `.cmd` and `.ps1` shims in addition to the binary itself. Directly invoking the raw `.js` binary file or relying on Unix-style symbolic link behavior might not work as expected in standard Windows command prompts.
- gotcha For global package installations, `bin-links` (via npm's internal logic) will only overwrite existing binaries if they were previously installed by the *same* package. This is a security measure to prevent arbitrary file overwrites. Using `force: true` might not bypass this specific safety check for global installs in all npm versions.
Install
-
npm install bin-links -
yarn add bin-links -
pnpm add bin-links
Imports
- binLinks
const binLinks = require('bin-links');import binLinks from 'bin-links';
- binLinks.getPaths
import { getPaths } from 'bin-links';import binLinks from 'bin-links'; const paths = await binLinks.getPaths({ /* ... */ }); - binLinks.checkBins
import { checkBins } from 'bin-links';import binLinks from 'bin-links'; await binLinks.checkBins({ /* ... */ });
Quickstart
const binLinks = require('bin-links');
const path = require('path');
const fs = require('fs/promises');
// Simulate a package.json read for demonstration
async function readPackageJson(packagePath) {
try {
const pkgContent = await fs.readFile(packagePath, 'utf8');
return JSON.parse(pkgContent);
} catch (err) {
// Create a dummy package.json content if file not found
return {
name: 'some-package',
version: '1.0.0',
bin: {
'my-cli': 'cli.js'
},
man: [
'man/my-cli.1'
]
};
}
}
async function runBinLinkingExample() {
// Define paths relative to the current script execution
const tempDir = path.join(__dirname, 'temp-link-test');
const packageDir = path.join(tempDir, 'node_modules', 'some-package');
const binDir = path.join(tempDir, 'node_modules', '.bin');
const manDir = path.join(tempDir, 'share', 'man');
// Ensure necessary directories exist
await fs.mkdir(packageDir, { recursive: true });
await fs.mkdir(binDir, { recursive: true });
await fs.mkdir(path.join(packageDir, 'man'), { recursive: true });
await fs.mkdir(manDir, { recursive: true });
// Create dummy executable and man page files
await fs.writeFile(path.join(packageDir, 'cli.js'), '#!/usr/bin/env node\nconsole.log("Hello from my-cli!");', { mode: 0o755 });
await fs.writeFile(path.join(packageDir, 'man', 'my-cli.1'), '.TH "MY-CLI" "1" "2025-01-01" "1.0.0" "My CLI Manual"\n.SH NAME\nmy-cli - A sample command-line interface', { recursive: true });
const pkg = await readPackageJson(path.join(packageDir, 'package.json'));
console.log('Attempting to link binaries and man pages for ' + pkg.name + '...');
try {
await binLinks({
path: packageDir,
pkg: pkg,
global: false, // Set to true for global install simulation
top: true, // This is the top-level package being linked
force: true // Overwrite existing links if any
});
console.log('Binaries and man pages linked successfully!');
// Demonstrate checking for conflicts (should pass with force: true)
await binLinks.checkBins({
path: packageDir,
pkg: pkg,
global: false,
top: true,
force: true
});
console.log('No conflicting bins found (or forced overwrite).');
// List potential link paths (does not touch filesystem)
const potentialPaths = binLinks.getPaths({
path: packageDir,
pkg: pkg,
global: false,
top: true
});
console.log('Potential link paths:', potentialPaths);
} catch (error) {
console.error('Error during binary linking example:', error.message);
} finally {
// Clean up temporary directory after example
await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {});
console.log('Cleanup complete.');
}
}
runBinLinkingExample();