Migrating to 1.0
Most setups need no changes, but automatically discovered config files can now take precedence over package.json. Review Config files before upgrading. CLI flags, environment variables, GitHub status names and exit codes remain supported. This page lists everything that behaves differently. CONTRACT.md lists what stays compatible.
1.0 is a new major version, so ^0.x and ~0.x ranges don't pick it up: nothing changes until you upgrade. Most of what follows applies equally if you're coming from 0.3.x.
Upgrade by hand
- Use Node.js 22.17 or later, in CI too. Node.js 16, 18 and 20 are end-of-life.
- Update BundleWatch:
npm install bundlewatch@1 --save-devpnpm add bundlewatch@1 --save-devyarn add bundlewatch@1 --devbun add bundlewatch@1 --dev- Go through Things to check below.
- Build, then run
npx bundlewatch, keeping any existing globs or--config <path>arguments. Verify that it checks the intended files and limits.
Upgrade with an AI agent
Copy this prompt into your coding agent to upgrade a project:
Upgrade BundleWatch to 1.0 in this repository.
Read https://bundlewatch.io/guide/migrating-to-v1.md for what changed, and https://bundlewatch.io/llms-full.txt for the whole documentation. Then:
1. Update BundleWatch to the latest 1.x version, with the package manager this project uses. It needs Node.js 22.17 or later: update the Node.js version used in CI if it's older.
2. Check the configuration against "Things to check" in the migration guide, and follow its links. Look for bundlewatch.config.* files that now take precedence over the package.json bundlewatch key, and preserve the files and limits checked by each existing command. A numeric "maxSize" is now enforced: if a file now fails a limit that was never checked before, don't raise the limit, tell me.
3. On GitHub Actions, switch to the workflow's GITHUB_TOKEN as described in the guide, and remove workarounds that 1.0 makes unnecessary, such as CI_BRANCH_BASE set only to avoid comparing with master, or CI_COMMIT_SHA set to the pull request's head commit.
4. Remove the brotli-size dependency if nothing else uses it.
5. Build, then run `npx bundlewatch` with any existing globs or `--config <path>` arguments, and verify that it checks the intended files and limits. Summarize what you changed, what now behaves differently, and what is left for me to do, such as deleting a token secret that is no longer used.Things to check
- A discovered
bundlewatch.config.*file now takes precedence over thebundlewatchkey inpackage.json. Check which files and limits each existing command should use. If a config file is only for a separate--configcommand, rename it outside the discovery list and update that command so a bare run keeps usingpackage.json. See Config files. - A numeric
maxSize, such as102400, is now enforced. If a file now fails, it was over its limit before too: see Numeric maxSize. filesandci.trackBranchesreplace the defaults instead of merging with them: see Tracked branches.- On GitHub Actions, pushes are compared with the default branch instead of
master: see Base branch on GitHub Actions. - Pull request builds no longer save baselines: see Pull request builds.
- Tokens of users without push access will stop saving baselines: see Service changes.
- Deep imports into
bundlewatch/lib/…no longer work, exceptbundlewatch/lib/appandbundlewatch/lib/app/index.js: see Loading the package. - Behind a proxy, see Proxy variables. On GitHub Enterprise, see GitHub Enterprise.
What changed
Loading the package
import bundlewatch, { STATUSES } from 'bundlewatch'andrequire('bundlewatch').default/.STATUSESwork as before.- The package ships both ES module and CommonJS builds, with TypeScript types.
bundlewatch/lib/appandbundlewatch/lib/app/index.jsstill load the main export, withimportorrequire(), and runningnode_modules/bundlewatch/lib/bin/index.jsdirectly still runs the CLI.- Other deep imports into
bundlewatch/lib/…don't; use the package's main export.
Short results links
- Previously the results were packed into the URL and shortened with Firebase Dynamic Links, a product Google has shut down. Large projects produced URLs that browsers and servers refused (issues #404 and #456).
- Now, when the service accepts your token for writing, the link is short:
https://service.bundlewatch.io/r/<id>. See Results links for when it isn't. - Each run with a token makes one more request to the service, to create the short link. It gives up after 5 seconds and falls back to the long link.
- Existing
/results?d=…links keep working, including those with an unlimitedmaxSize, which never rendered before. Oldja2r7.app.goo.glshort links work for as long as Google keeps redirecting them.
bundlewatchServiceHost: null
With the service disabled, no results link is printed, the GitHub status has no details link, and the Node.js API returns url: undefined. Before 1.0 the link pointed to null/results?d=….
Service URLs with credentials
Basic auth credentials in bundlewatchServiceHost URLs (https://user:pass@…) keep working, and no longer appear in results links: 0.x printed them in the CI log and posted them as the GitHub status's details link. See bundlewatchServiceHost.
Base branch on GitHub Actions
- Pull request builds already compared with the pull request's target branch.
- Other builds, such as pushes, now compare with the repository's default branch instead of
master(issues #423 and service #280). - Setting
CI_BRANCH_BASEorci.repoBranchBasestill overrides this. If you setCI_BRANCH_BASEonly to avoidmaster, remove it: it also replaces the target branch of pull requests. See Base and tracked branches.
Pull request statuses on GitHub Actions
- Statuses are now reported on the pull request's head commit.
- Previously they went to
GITHUB_SHA, a temporary merge commit, so they didn't appear on the pull request unless you setCI_COMMIT_SHAyourself. Setting it still works.
Tracked branches
- The default
trackBranchesis now['master', 'main', 'develop'], plus the repository's default branch on GitHub Actions. trackBranchesandfilesarrays in your configuration now replace the defaults. Previously they were merged index by index, sotrackBranches: ['main']actually tracked['main', 'develop'].
Pull request builds no longer save baselines
Pull request builds compare with the baseline but no longer save one. Previously, a pull request whose head branch had a tracked name, such as a fork's master, overwrote the real master baseline with its own sizes.
See Pull request builds for which builds count.
Numeric maxSize
A numeric maxSize such as 102400 is now enforced. Previously it was silently ignored and the check always passed. If your bundle is over a numeric limit, BundleWatch now reports it.
0, whether a number or a string such as '0' or '0kB', still means no limit.
Other fixes
- On GitHub Actions push builds, branch names containing
/are read correctly: 0.x read a push tofeat/fooasfeat(issue #422). - A run where some files are missing or can't be read no longer sends a baseline. The service rejected those anyway; the CLI now logs why.
- With
compression: 'none', empty files are measured as 0 B instead of failing withCould not read file. gzip and brotli already measured them, as 20 B and 1 B. - Removed files named after an
Object.prototypeproperty, such asconstructor, now show as removed instead of passing with no size. New files with those names get a zero-byte baseline. A file whose normalized path is exactly__proto__is now measured and checked instead of dropped. - Running BundleWatch in a directory without a package.json no longer crashes (issue #434).
-Vand--versionprint the version. Other flags work as before, including a bare--max-sizefor no limit; see Command line.- With
CIset but noCI_REPO_OWNERandCI_REPO_NAME, BundleWatch falls back toGIT_URLinstead of using the repositoryundefined/undefined. - BundleWatch now discovers
bundlewatch.config.*files before falling back topackage.json. It searches from the current directory up to and including the nearestpackage.jsondirectory, checking.mjs,.js,.cjs,.mts,.ts,.ctsand.jsonin that order in each directory. The first file wins; without a package, the search continues to the filesystem root. A broken config fails without falling back.--configoverrides discovery and accepts absolute paths. It loads.mjsfiles, and configs with only named exports, withimport(), and it loads.ts,.mtsand.ctsfiles on Node.js 22.18 and later. See Using a config file.
Proxy variables
BundleWatch no longer reads HTTP_PROXY, HTTPS_PROXY, NO_PROXY or similar variables: 0.x used them only as a side effect of its HTTP library, and never documented them. Behind a proxy that blocks direct connections, see Troubleshooting.
Brotli
Brotli compression works without installing brotli-size, which you can remove. Node's built-in zlib produces identical sizes.
GitHub Enterprise
Commit statuses go to the GitHub API at GITHUB_API_URL when it is set; GitHub Actions on GitHub Enterprise Server sets it automatically. See GitHub Enterprise for the rest of the setup.
Upgrading from 0.3.x with normalizeFilenames
0.3.x saved every file that the pattern didn't match under an empty name. On the first 1.0 run those files show as new, and an empty-named entry shows as removed, until a tracked branch saves a new baseline.
Service changes (service.bundlewatch.io)
These apply to every CLI version, 0.x included.
WARNING
Before service.bundlewatch.io enforces the stricter check below, replace tokens of users without push access: create a new one at /setup-github as a user with push access, or use GITHUB_TOKEN on GitHub Actions.
POST /resultscreates a short link and needs write access (below);GET /r/{id}renders it.- Saving baselines and creating short links need stricter authorization, rolled out in report-only mode:
- To save, a token on a public repository must belong to a user with push access, or be an installation token for that repository, such as the
GITHUB_TOKENof its own workflows. - Previously, any GitHub token could overwrite a public repository's baseline.
- At first the service only logs requests the new rule would refuse.
- In report mode, the stricter check never changes a decision, even when it fails or times out.
- Reading a baseline works as before.
- To save, a token on a public repository must belong to a user with push access, or be an installation token for that repository, such as the
- Error codes changed:
- Malformed results links return
400instead of500. - Failures talking to GitHub return
503instead of401or500. - Baselines too large to store return
413instead of500.
- Malformed results links return
- The service now accepts baselines and links where
maxSizeis a size string such as"100KB". 0.x rejected these even though its CLIs sent them for a numericmaxSizein the config. /setup-githubchecks an OAuthstate. An authorization started in another browser, or more than 10 minutes earlier, has to be restarted.- Deployment uses AWS SAM and GitHub Actions OIDC, replacing the Serverless Framework v3 and CircleCI. See
packages/service/README.md.
Using the GitHub Actions token
If you run BundleWatch on GitHub Actions with a token from service.bundlewatch.io/setup-github, you can switch to the token GitHub creates for each workflow run: grant the workflow statuses: write, keep contents: read, and pass secrets.GITHUB_TOKEN as BUNDLEWATCH_GITHUB_TOKEN. The service accepts this token for saving baselines and creating short links. See GitHub Actions for a complete workflow.