Core factory functions for creating and resolving package managers automatically based on project configuration and lockfiles.
Creates the appropriate package manager for a project by detecting lockfiles or using explicit configuration.
/**
* Creates a Node package manager from the provided options.
* If options are not provided, it will infer the package manager from lockfiles.
* When no package manager is found, it falls back to npm.
*
* @param projectRoot - The root directory of the project
* @param options - Configuration options with optional package manager selection
* @returns NodePackageManager instance appropriate for the project
*/
function createForProject(
projectRoot: string,
options?: NodePackageManagerForProject
): NodePackageManager;
type NodePackageManagerForProject = PackageManagerOptions &
Partial<Record<NodePackageManager['name'], boolean>>;Usage Examples:
import { createForProject } from '@expo/package-manager';
// Auto-detect from lockfiles
const manager = createForProject('/path/to/project');
// Force specific package manager
const npmManager = createForProject('/path/to/project', { npm: true });
const yarnManager = createForProject('/path/to/project', { yarn: true });
// With additional options
const silentManager = createForProject('/path/to/project', {
silent: true,
log: console.debug
});Resolves the package manager used by a project by checking for lockfiles.
/**
* Resolve the used node package manager for a project by checking the lockfile.
* This also tries to resolve the workspace root, if its part of a monorepo.
* Optionally, provide a preferred packager to only resolve that one specifically.
*
* @param projectRoot - The root directory of the project
* @param preferredManager - Optional preferred package manager to check for specifically
* @returns Package manager name or null if none found
*/
function resolvePackageManager(
projectRoot: string,
preferredManager?: NodePackageManager['name']
): NodePackageManager['name'] | null;Usage Examples:
import { resolvePackageManager } from '@expo/package-manager';
// Detect any package manager
const detected = resolvePackageManager('/path/to/project');
// Returns 'npm', 'yarn', 'pnpm', 'bun', or null
// Check for specific package manager
const hasYarn = resolvePackageManager('/path/to/project', 'yarn');
// Returns 'yarn' if yarn.lock exists, null otherwiseResolves the workspace root directory for monorepo projects.
/**
* Resolves the workspace root directory if the project is part of a monorepo
*
* @param projectRoot - The current project directory
* @returns Workspace root path or null if not in a workspace
*/
function resolveWorkspaceRoot(projectRoot: string): string | null;Usage Examples:
import { resolveWorkspaceRoot } from '@expo/package-manager';
const workspaceRoot = resolveWorkspaceRoot('/path/to/nested/project');
if (workspaceRoot) {
console.log(`Part of workspace at: ${workspaceRoot}`);
// Create manager for workspace root
const rootManager = createForProject(workspaceRoot);
}Package managers are resolved in a specific order based on lockfile presence.
const RESOLUTION_ORDER: NodePackageManager['name'][] = ['bun', 'yarn', 'npm', 'pnpm'];
const NPM_LOCK_FILE = 'package-lock.json';
const YARN_LOCK_FILE = 'yarn.lock';
const PNPM_LOCK_FILE = 'pnpm-lock.yaml';
const BUN_LOCK_FILE = 'bun.lockb';
const BUN_TEXT_LOCK_FILE = 'bun.lock';The resolution process:
preferredManager is specified, only check for that manager's lockfilesRESOLUTION_ORDER: bun → yarn → npm → pnpmnull if no lockfiles are foundUsage Examples:
import { RESOLUTION_ORDER, BUN_LOCK_FILE } from '@expo/package-manager';
// Check resolution order
console.log('Checking in order:', RESOLUTION_ORDER);
// Check for specific lockfiles
import fs from 'fs';
import path from 'path';
const hasBunLock = fs.existsSync(path.join(projectRoot, BUN_LOCK_FILE));