Bandwidth
Median 96% fewer bytes per update across 8 real getsentry/cli
releases. A 31 MB gzipped full download becomes a 1.3 MB patch
on a typical release — and small bug-fix releases go as low as 0.9%.
Bandwidth
Median 96% fewer bytes per update across 8 real getsentry/cli
releases. A 31 MB gzipped full download becomes a 1.3 MB patch
on a typical release — and small bug-fix releases go as low as 0.9%.
Wall time
On slow links the savings are dramatic. At 5 Mbps the full download takes ~53 s; the patch download + apply takes ~4 s. At 25 Mbps it’s ~11 s vs ~2 s.
User patience
The fastest update is the one that finishes before the user opens Twitter. Patch downloads feel instantaneous on any link.
The classic case: a mycli update command downloads and applies the
next version. Especially good fits:
bun build --compile) — embed a JS/TS entry into a standalone
executable.deno compile) — Deno’s equivalent.node --experimental-sea-config + node --build for
SEA.Powers self-updates in production for shipped binaries you may already be using — including Sentry’s own getsentry/cli.
Every auto-update today fetches the full .dmg / .exe / .AppImage.
binpatch works the same way: ship a small patch alongside the full
artifact, and your updater picks the patch when the old version is
known.
The wire format and discovery (ghcrSource / githubReleaseSource)
are generic — point them at your updater’s existing release channel.
Long-running agents (deploy agents, observability daemons, ML inference runtimes) update in-place without a restart. The patch download is small enough to do opportunistically on every poll, and apply time is predictable (~3–8 s per hop on the Sentry CLI binary).
Game launchers, native installers, anything that ships as a single artifact. As long as you can identify the user’s installed version, binpatch can deliver a delta. Native binaries with lots of relocatable code compress especially well — sub-1% patches are common.
A patch is useless without both:
old → new in CI, and publish it
somewhere your users can find it.And if the user is several versions behind, they don’t get a single patch — they get a chain of patches. binpatch chains them automatically, downloads them in parallel, applies each hop in order, verifies the cumulative SHA-256, and falls back to a full download if any hop is missing or malformed.
Most projects hand-roll one half and skip the other. binpatch gives you
both, as a small MIT-licensed TypeScript library plus a drop-in GitHub
Action. See the GitHub Action page for how an end-to-end
update flows through the system.
npm install binpatchThen both: generate patches from CI with the
GitHub Action (so nightly builds push to GHCR and
stable releases push to GitHub Releases), and wire
resolveAndApply into your binary’s update command
to discover and apply them.
import { resolveAndApply } from "binpatch";
const result = await resolveAndApply({ currentVersion: "1.2.0", targetVersion: "1.3.4", source: ghcrSource({ repo: "myorg/mycli" }),});// result.destPath now holds the verified 1.3.4 binary; download was ~1 MB.