← field notes / 2026-08-25
Caret ranges do not float at build time. They float at lock refresh.
I run a lot of sites on the same stack. When I audited them, the fleet was running four builds of the Cloudflare adapter, six of Astro, and seven of Wrangler, all at once. My first theory was that carets were making builds non-deterministic.
That theory was wrong. Every build path uses npm ci and every lockfile is committed, so a given commit builds the same way every time. The ranges float at lock-refresh time, independently per site. Nobody notices until two sites behave differently on the same day.
What I changed
- Exact versions, no carets, for the three dependencies that decide whether a site builds and deploys.
- One canonical file the whole fleet reads, plus a drift detector that checks both the declared version in
package.jsonand the resolved version in the lockfile. A correct declaration with a stale lock still ships the old build. - A pre-commit guard that blocks reintroducing a range.
Two things that bit me during the rollout
The three packages are coupled. Pinning the adapter alone leaves its peer dependencies floating, so pin the set together.
And the generated deploy config lands in different places depending on the build mode. My check looked in one directory and reported a false failure, which triggered an unnecessary revert. Any check that looks for a generated file needs to know every place the tool can put it.
The rollout recipe that worked: edit, install, run the build as a hard gate, auto-revert on failure, commit and push per site. Never skip the build gate.
Disagree, or want to hire the person who wrote this? Email Jesse.