Pacote: JavaScript Package Downloader
Pacote is a robust JavaScript library designed for programmatically fetching package manifests and tarballs, primarily from the npm registry but also supporting various other package specifiers like Git repositories, local directories, and tarball URLs. It is the underlying package fetching mechanism used by the npm CLI itself, ensuring high compatibility with npm's ecosystem. The current stable version is 21.5.0, released in March 2026, and the project demonstrates an active release cadence with frequent updates across major versions (e.g., v19, v20, v21 receiving simultaneous updates). Key differentiators include its ability to resolve any npm-compatible package specifier, simulate packument data for non-registry sources, and run `prepare` scripts for Git or directory-based packages to replicate the publishing process. It provides APIs for resolving package URLs, extracting contents to a directory, fetching manifests, and downloading tarball data as buffers or streams.
Common errors
-
Error: Command failed with exit code 1
cause Often occurs when `prepare` scripts within a fetched package (especially from Git or local directory) fail during execution.fixInspect the full error output for details from the failed script. Ensure the environment has necessary build tools and dependencies for the package's `prepare` script. You might need to adjust options to skip `prepare` if not critical. -
Error: Unsupported specifier: <your-package-specifier>
cause The provided package specifier (e.g., `foo@^1.0`, `github:user/repo`, `file:../path`) is malformed or not recognized by Pacote/npm-package-arg.fixVerify the package specifier against `npm-package-arg` documentation and examples. Ensure correct syntax for versions, ranges, Git URLs, and local paths. -
ETIMEDOUT
cause Network issues, incorrect registry configuration, or proxy problems preventing connection to the npm registry or other package sources.fixCheck your network connection, npm proxy settings, and ensure your `.npmrc` or programmatic options have the correct `registry` and authentication (e.g., `_authToken`) configured. -
Error: Cannot find module 'pacote'
cause Package `pacote` is not installed, or there is a module resolution issue (e.g., wrong import path, CJS/ESM mismatch in an improperly configured project).fixEnsure `pacote` is listed in `dependencies` and `npm install` has been run. Verify import statement (`const pacote = require('pacote');` for CJS or `import pacote from 'pacote';` for ESM) matches your project's module system and Node.js configuration.
Warnings
- breaking Pacote now requires Node.js version `^20.17.0 || >=22.9.0`. Older Node.js environments will result in runtime errors. Ensure your environment meets these minimum requirements.
- gotcha When fetching packages from Git repositories or local directories, Pacote automatically executes `prepare` scripts to simulate the build process as if it were being published to the registry. This can have side effects, introduce unexpected build times, or require specific environment configurations if not properly anticipated.
- gotcha Pacote's configuration options (`opts` parameter) mirror npm's CLI configuration. Incorrectly setting options like `cache`, `registry`, or authentication tokens can lead to unexpected fetching behavior, authentication failures, or network errors. Utilize the recently introduced `allowRegistry`, `allowRemote`, `allowFile`, `allowDirectory`, and `allowGit` options to explicitly control allowed package sources, as misconfiguration could unintentionally block valid package types.
- gotcha The `integrity` field, especially for Git sources, can be complex. Recent versions (e.g., v21.3.1 fix for `git ref matches expected sha`) highlight potential for inconsistencies in how Git references are resolved. Always verify the resolved `integrity` and `resolved` fields for critical dependencies.
- gotcha The introduction of 'attestation bundles' in v21.5.0 provides a security layer. While beneficial, it might introduce overhead or unexpected network requests if the registry or network setup doesn't fully support it, potentially impacting performance or causing errors if validation fails.
Install
-
npm install pacote -
yarn add pacote -
pnpm add pacote
Imports
- pacote
import { pacote } from 'pacote'; // Incorrect named import, pacote exports a default object.import pacote from 'pacote';
- pacote (CommonJS)
const pacote = require('pacote'); - pacote.manifest
import { manifest } from 'pacote'; // Manifest is a method on the default export, not a named export.import pacote from 'pacote'; const manifest = await pacote.manifest('foo@latest');
Quickstart
const pacote = require('pacote');
const path = require('path');
const fs = require('fs/promises');
async function main() {
const packageName = 'lodash';
const packageVersion = '4.17.21';
const gitSpec = 'github:npm/cli';
const tarballUrl = 'https://registry.npmjs.org/is-odd/-/is-odd-3.0.1.tgz';
console.log(`--- Fetching manifest for ${packageName}@${packageVersion} ---`);
try {
const manifest = await pacote.manifest(`${packageName}@${packageVersion}`);
console.log(`Got manifest for ${manifest.name}@${manifest.version}`);
console.log(`Dependencies: ${Object.keys(manifest.dependencies || {}).join(', ') || 'None'}`);
} catch (error) {
console.error(`Failed to fetch manifest: ${error.message}`);
}
console.log(`\n--- Extracting ${gitSpec} to a temporary path ---`);
const tempExtractPath = path.join(__dirname, 'temp-extracted-repo');
try {
await fs.mkdir(tempExtractPath, { recursive: true });
const { from, resolved, integrity } = await pacote.extract(gitSpec, tempExtractPath);
console.log(`Extracted '${from}' (resolved to '${resolved}') with integrity '${integrity}' to '${tempExtractPath}'`);
const files = await fs.readdir(tempExtractPath);
console.log(`Extracted files (first 5): ${files.slice(0, 5).join(', ')}...`);
} catch (error) {
console.error(`Failed to extract package: ${error.message}`);
} finally {
await fs.rm(tempExtractPath, { recursive: true, force: true });
}
console.log(`\n--- Downloading tarball from ${tarballUrl} ---`);
try {
const tarballData = await pacote.tarball(tarballUrl);
console.log(`Got ${tarballData.length} bytes of tarball data. Resolved URL: ${tarballData.resolved}`);
} catch (error) {
console.error(`Failed to download tarball: ${error.message}`);
}
}
main().catch(console.error);