@manypkg/get-packages

Async and sync APIs that discover every package in a Yarn, npm, pnpm, Bun, Lerna, or Rush monorepo.

Library
npm
v3.1.0
1,045stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
63/100Good
Development Activity36
Maintenance52
Community64
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
70/100Good
Architecture85
Code Quality78
Innovation70
Learning Curve45

@manypkg/get-packages is the package-discovery core of Thinkmill’s manypkg toolkit. Given any directory inside a repository, it walks upward to find the monorepo root, detects which workspace tool manages it (Yarn, npm, pnpm, Bun, Lerna, Rush, or a plain single-package repo), and returns every package’s parsed package.json alongside its absolute and relative directory paths.

It underpins @manypkg/cli’s linting and fixing of package.json inconsistencies across workspaces, and is built for reuse by other monorepo tooling that needs to enumerate packages without re-implementing tool-specific glob and lockfile parsing for every package manager.

What You Get

  • Automatic tool detection - Walks up from any starting directory to find and identify whether the repo uses Yarn, npm, pnpm, Bun, Lerna, Rush, or a single root package.
  • Unified package list - Returns a consistent Packages object with parsed packageJson, absolute dir, and relativeDir for every workspace member regardless of which tool manages it.
  • Sync and async entry points - getPackages and getPackagesSync cover both promise-based and blocking call sites.
  • Name-field validation - Throws a PackageJsonMissingNameError listing every package.json missing a required name field instead of failing on the first one found.
  • Pluggable tool list - Accepts a custom tools array to restrict or extend which monorepo implementations are checked.

Common Use Cases

  • Building custom monorepo scripts that need to iterate over every internal package, such as running a command per package.
  • Writing linting or codemod tools that check package.json consistency across a workspace, as @manypkg/cli itself does.
  • Implementing release tooling that needs to know a monorepo’s package graph without shelling out to the package manager.
  • Building editor, IDE, or dashboard tooling that needs a live, tool-agnostic list of packages in a repository.

Under The Hood

Architecture getPackages(dir) calls findRoot from @manypkg/find-root, which walks up directories testing each registered Tool’s isMonorepoRoot until a match is found, then getPackages delegates to tool.getPackages(rootDir) from @manypkg/tools and finally runs validatePackages, which checks every discovered package.json for a name field and throws a single PackageJsonMissingNameError listing all offenders if any are missing. The architecture is intentionally thin: get-packages is a small orchestration layer with no tool-specific logic of its own — all package-manager detection (Yarn’s workspaces field, pnpm-workspace.yaml, npm workspaces, Bun’s workspaces, Lerna’s lerna.json, Rush’s rush.json) lives in the sibling @manypkg/tools package behind a common Tool interface, and the upward directory-walking algorithm lives in @manypkg/find-root. This separation means adding support for a new package manager only requires a new Tool implementation registered in DEFAULT_TOOLS, with no change to get-packages itself.

Tech Stack A TypeScript ESM package (type: module) built via @preconstruct/cli alongside its sibling packages in the manypkg Yarn workspace, tested with Vitest and the fixturez fixture-copying library for repo-based integration tests. Its only dependencies are two sibling workspace packages, @manypkg/find-root and @manypkg/tools, with zero third-party runtime dependencies. It targets Node >=20. The wider monorepo uses Changesets for versioning and publishing, TypeScript in strict mode, and Knip for unused-code detection, with GitHub Actions running CI.

Code Quality index.test.ts exercises both getPackages and getPackagesSync against real fixture repositories for every supported tool — yarn, npm, pnpm (including exclude rules), bun (including JSON-lock and object-form workspaces), lerna (with and without explicit package globs), a single root-only package, a missing-name-field case, and a cyclic local-dependency case — copied fresh per test via fixturez rather than mocked. Errors are explicit, typed classes (PackageJsonMissingNameError, and NoPkgJsonFound/NoMatchingMonorepoFound in the sibling find-root package) carrying descriptive, actionable messages rather than generic throws. Naming and types are consistent throughout, with shared types (Packages, Package, MonorepoRoot) re-exported directly from @manypkg/tools instead of being redefined.

API Design The public surface is deliberately narrow: two functions (getPackages, getPackagesSync), one options type, and one error class, with zero configuration required for the common case and a single escape hatch (the tools option) for advanced callers who want to restrict or extend detection. JSDoc comments annotate every exported symbol, and the returned Packages shape is symmetric across every supported tool so calling code never needs per-tool branching. The tradeoff is that understanding the full detection behavior requires reading the sibling @manypkg/tools package, since none of the tool-specific logic is visible from get-packages alone.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search