Skip to main content

Delta patches

Most React Native bundles change by a few kilobytes between releases. Shipping the entire 5–10 MB bundle every time wastes bandwidth and battery for no reason. Swiftpatch's delta patches fix that with zero configuration — you deploy normally, and the server emits patches against the last five releases automatically.

Typical savings: 60–98%. A 10 MB bundle with a small code change produces a patch of 100–400 KB.

How it works

┌──────────────────────────────┐
│ Server: bsdiff generator │
│ │
│ When you ship r_new: │
│ • Compute bsdiff(r_last, r_new) │
│ • Compute bsdiff(r_last-1, r_new) │
│ • ... for last 5 releases │
│ • Store each .bsdiff blob on R2 │
└───────────────┬──────────────┘


┌──────────────────────────────┐
│ /sdk/check-update response │
│ { │
│ release: r_new, │
│ patches: [ │
│ { fromHash: r_last, │
│ patchUrl, patchSize } │
│ { fromHash: r_last-1, │
│ ... }, │
│ ... │
│ ] │
│ } │
└───────────────┬──────────────┘


┌──────────────────────────────┐
│ SDK patch picker │
│ │
│ 1. Find the patch whose │
│ fromHash == device's │
│ current bundle hash. │
│ 2. Pick the smallest one. │
│ 3. Download + verify + apply│
│ 4. Fall back to full bundle │
│ on ANY failure. │
└──────────────────────────────┘

The pipeline

  1. Check. Device calls /sdk/check-update with its current bundle hash. The server returns the new release + a patches[] array with one patch per prior release hash.
  2. Pick. The SDK selects the patch whose fromHash matches the device's current bundle. If no patch matches, it downloads the full bundle.
  3. Verify the patch. The patch bytes are Ed25519-signed. The SDK verifies the signature before feeding them to bspatch.
  4. Apply. Native bspatch (iOS + Android share the same vendored BSD-2-clause C library) reconstructs the new bundle.
  5. Verify the output. SHA-256 of the reconstructed bundle is checked against the advertised target hash.
  6. Commit. Atomic slot promotion.

If any step fails, the SDK silently falls back to downloading the full bundle. A PATCH_FALLBACK_TO_FULL telemetry event fires so you can see degraded patch paths in the dashboard.

Safety guarantees

  • Signed patches. The patch blob itself is signed — not just the reconstructed output. A tampered patch can't reach bspatch.
  • Output hash verification. The patched output is SHA-256-checked against the target hash. If bsdiff was run on the wrong base, the check fails and the SDK falls back.
  • Never corrupts the active slot. Patches are applied in a staging directory and atomically renamed on success. A mid-apply crash leaves the old active slot intact.

Telemetry

Two events fire from the patch pipeline:

  • PATCH_APPLIED_PROD — successful delta apply. Payload includes bytesSaved so you can graph bandwidth savings in your dashboard.
  • PATCH_FALLBACK_TO_FULL — patch path failed. Payload includes failureKind:
    • patch_verify_failed — signature mismatch.
    • bspatch_failed — corrupt or truncated patch stream.
    • output_hash_mismatch — base drift (the device's current bundle wasn't the declared fromHash).
    • base_missing — the current bundle file is absent (rare, only after filesystem corruption).
    • patch_download_failed — network error fetching the patch.

All of these are non-fatal. The full bundle ships next.

Why bsdiff?

Two reasons:

  1. Proven. bsdiff (Colin Percival, 2003) is the basis of FreeBSD's binary updates, macOS updates, and countless other systems. The algorithm is mature and the patches are dense.
  2. Language-agnostic. The C reference implementation compiles cleanly on both iOS and Android. A single source file ships on both platforms.

The SDK uses the BSD-2-clause reference implementation with no modifications beyond a categorized error-code wrapper (sp_bspatch) for telemetry.

Configuration

There is no configuration. The server emits patches automatically for every release. The SDK picks the best patch and falls back to full bundles when needed. Your deploy command doesn't change:

swiftpatch deploy -p ios --hermes

The CLI uploads the full bundle. The server generates patches against the last 5 releases and caches them on R2. Your job is done.

Monitoring savings

In the dashboard, the Releases page shows per-release delta-patch metrics:

  • Percent of downloads that used the patch path (vs. full).
  • Total bytes saved.
  • Patch ratio histogram (distribution of patch sizes as a percent of full bundle).
  • Fallback rate (PATCH_FALLBACK_TO_FULL events per release).

Next steps