Trust these instructions. Only search the codebase if information here is incomplete or found to be in error (notify the user if an error is found). Following these steps will minimize failed commands and CI rejections.
Beachball is a CLI tool for automating semantic version bumping, changelog generation, and npm publishing in monorepos and single-package repos. This repo is a Yarn 4 monorepo of ~2,000 files. The main deliverable is the beachball npm package.
- Runtime: Node.js
>=22.23.4(repo developed on Node 22; CI also runs Node 24). TypeScript files can be run directly withnode(no extra flags). - Language: TypeScript
~6.0. Thebeachballandp-graphpackage output is CommonJS (other packages use ESM). - Package manager: Yarn 4 (Berry),
nodeLinker: node-modules. Some dependency versions are shared via Yarn catalogs (catalogsin .yarnrc.yml). Never usenpm install. - Task runner: lage orchestrates
build,test,lintacross workspaces (config: lage.config.js). - Testing: Jest 30 via Babel.
- Linting/formatting: ESLint 9 flat config + Prettier.
- Dependency consistency: syncpack + depcheck.
main(default): development for beachball v3 (alpha). Breaking changes allowed.v2: current stable release. Non-breaking changes should targetv2.
Always run yarn --immutable first if dependencies may be out of date.
When validating the entire repo, run the following commands in order:
| Step | Command | Notes / timing (validated) |
|---|---|---|
| Install | yarn --immutable |
Required before any build/test/lint. |
| Build | yarn build |
~8s. Runs lage build bundle across all workspaces. |
| Lint | yarn lint |
~10s. Runs eslint + depcheck + syncpack via lage. |
| Test (all) | yarn test |
Runs all workspace tests via lage. |
| Update snapshots | yarn update-snapshots |
Use after intentional output changes. |
Do NOT run jest or tsc directly from the repo root. yarn build and yarn lint must succeed with zero warnings.
The pre-commit hook runs Prettier (yarn format) automatically on all staged files using lint-staged. Do not manually run yarn format, Prettier, or a formatting check after routine edits. Run formatting commands only when explicitly requested, when preparing a PR without committing locally, or when diagnosing a formatting failure.
When developing in a single package, use these commands first before building/validating the entire repo. Run cd packages/<name> then:
| Task | Command |
|---|---|
| Build a single package | yarn build |
Test (packages other than beachball) |
yarn test |
(beachball) All tests, correct order |
yarn test:all |
(beachball) All unit tests |
yarn test:unit (~3s) |
(beachball) All functional tests |
yarn test:func |
(beachball) All E2E tests |
yarn test:e2e (slow) |
| Single test file/name (wraps jest), ANY package | yarn test <path or name> |
| Update snapshots | yarn update-snapshots |
In the beachball package, do NOT use test:* commands to run a single test. Use yarn test <path or name>.
Prefer scripts over running binaries directly. If you must run a binary such as jest, use yarn run -T <binary>.
Run all of: yarn build, yarn test, and yarn lint. Prettier runs automatically in the pre-commit hook.
- Use the
/beachball-change-fileskill to generate a Beachball change file if needed. Sometimes it's not needed, but verify by runningyarn checkchange(CI also runs this). - Check whether documentation site or CLI help text updates are needed.
packages/beachball— main package (see architecture below).packages/p-graph— promise graph runner, used bybeachball.packages/proper-changelog— changelog/release notes helper.packages/esrp-npm-release— helper for the Microsoft release process.scripts— repo-internal scripts (@microsoft/beachball-scripts); shared build/test/eslint config lives in scripts/config.actions/*— GitHub Action definitions (check-for-modified-files,install-beachball,should-release); theirdist/is committed and must be rebuilt viayarn build+yarn bundleifsrcchanges.yarn-plugins/*— Yarn v4 plugins (engines,npmrc) loaded by the repo's own .yarnrc.yml. Each builds a bundle viayarn build+yarn bundleinto a committeddist/plugin.js, which must be rebuilt and committed ifsrcchanges. See yarn-plugins/README.md.renovate/- Renovate presets migrated fromm365-renovate-config; scripts underrenovate/scripts; presets underrenovate/presets; auto-updated readmedocs/— Vuepress documentation site with its own separate Yarn install.change/— pending Beachball change files (JSON).- Root config: beachball.config.js, lage.config.js, syncpack.config.js, .prettierrc.json5, .yarnrc.yml. Per-package:
tsconfig.json,jest.config.js,eslint.config.*.
- Entry point:
src/cli.tsdispatches commands:check,change,bump,publish,canary,sync,init,config. src/commands/— command implementations.src/bump/— version bump calculation (bumpInMemoryis the core algorithm).src/changefile/— reading/writing/prompting for change files.src/changelog/— changelog generation (markdown + JSON).src/monorepo/— package discovery (workspace-tools), dependency graph, package groups.src/publish/— npm publish orchestration, git tagging, dependency-ordered publishing.src/git/— git operation wrappers using nano-spawn.src/options/— CLI arg parsing + config loading.src/validation/— pre-command validation.src/types/— TypeScript interfaces (BeachballOptionsis the central config type).- Option resolution: CLI args > config (usually
beachball.config.js) > defaults.getOptions()returns both rawcliOptionsand mergedoptions.
- No global state:
process.cwd(),process.chdir(), andprocess.exit()are banned via ESLint. Pass an explicitcwd.process.exit()may only be used incli.ts. - Imports: use
import "fs/promises"directly (notfs.promises) to enable Jest mocking. Useimport typefor type-only imports (enforced). - Naming: camelCase or PascalCase; unused parameters prefixed with
_. - Style: Prettier — single quotes, 120 char width, ES5 trailing commas.
- Markdown: use sentence case for headings. NEVER manually wrap lines in
.mdfiles (except within code blocks).
packages/beachball has three Jest projects: unit (src/__tests__/, no filesystem), functional (src/__functional__/, realistic setups / real filesystem), e2e (src/__e2e__/, full commands, uses verdaccio). Fixtures/mock factories are in src/__fixtures__/.
- Import Jest APIs from
@jest/globals(no implicit globals). - Prefer real generator functions or
__fixtures__helpers over hand-building complex objects (PackageInfos,ChangeInfo,BumpInfo,BeachballOptions). - When testing a function with complex parameters, consider creating a wrapper function in the test which fills in common defaults.
- Any test that writes to the console must call
initMockLogs(). - Beachball's logs are its UI. Often, tests should include complete inline snapshots of output (especially if it's only a few lines).
- Prefer complete value assertions (
toEqual({...}),toEqual([...])) over partial matchers.
Vuepress site under docs/ with a separate Yarn install. (Ignore docs/v2/ when reading or updating documentation unless the task explicitly targets the v2 docs.)
To edit/validate:
cd docs && yarn --immutable(install docs deps first).yarn docs:buildto validate.- When adding a new page, you MUST add it to the sidebar in
docs/.vuepress/config.ts.
You must update the doc site when adding a new option or command.
Defined in .github/workflows/pr.yml. Replicate locally with the commands above.
- build job (ubuntu + windows, node 22/npm 10 and node 24/npm 11):
yarn --immutable,yarn build --verbose,yarn checkchange --verbose,yarn format:checkandyarn lint --verbose(ubuntu/node22 only),yarn test --verbose, plus extra Windows-bash tests. - actions job: builds, then runs
check-for-modified-files— if actiondist/changed, runyarn buildand commit the updateddistfiles. - docs job:
cd docs && yarn --immutable && yarn docs:build.