OTA Update Strategies: Delta vs Full Firmware (What to Use When)

OTA update strategies: Delta vs Full firmware is one of the most practical design decisions you will make for any connected device, because it directly impacts bandwidth, failure rates and support cost. This comparison is for intermediate embedded and IoT engineers who already ship firmware and now want a clearer, more quantitative way to choose between delta (patch) updates and full image updates.
What you will get: a side-by-side comparison, sizing math, security and rollback considerations, and two working code examples (one for generating and applying delta patches, one for a resumable full-image downloader with integrity checking).
Table of Contents
- OTA update strategies: Delta vs Full firmware
- How delta and full OTA updates work
- Bandwidth, time and cost modeling
- Flash layout, bootloader and rollback implications
- Reliability, failure modes and resume
- Security and compliance considerations
- Code example 1: Generate and apply delta patches
- Code example 2: Resumable full firmware download with integrity
- Platform and protocol fit (MQTT, HTTP, CoAP)
- Decision matrix: what to choose
- Practical recommendations
OTA update strategies: Delta vs Full firmware
At a high level, you have two ways to deliver new firmware over-the-air (OTA):
- Full firmware OTA: you download an entire new firmware image (or partition) and boot into it after verification.
- Delta firmware OTA (also called patch-based OTA): you download a compact âdifferenceâ between the old and new firmware and reconstruct the new image on the device.
This choice is not only about âsmaller download is betterâ. Delta updates can reduce network load dramatically, but they increase update complexity, require careful version management and can worsen failure handling if you do not design for resume and rollback. Full image updates are simpler and more robust across heterogeneous device states, but can be expensive on metered links and slow on constrained radios.
How delta and full OTA updates work
Full firmware update flow
- Device checks: device contacts your update service (HTTP(S), MQTT (Message Queuing Telemetry Transport), CoAP (Constrained Application Protocol) or vendor service) and asks for an update.
- Download: device downloads a complete image (often to an âinactiveâ partition).
- Verify: device verifies integrity (hash) and authenticity (signature).
- Swap: bootloader selects the new image (A/B scheme) or installs it in place (single-slot with staging).
- Commit or rollback: after successful boot and health checks, the device commits. If boot fails, it rolls back.
Diagram (described): Think of flash split into two equal âslotsâ, Slot A (active) and Slot B (inactive). You download to Slot B, verify, then set âboot next = Slot Bâ. If it boots and passes health checks, mark Slot B as âconfirmedâ and keep Slot A as rollback.
Delta firmware update flow
- Baseline identification: device reports its current firmware version and sometimes a build hash (not only a semantic version).
- Patch selection: server selects a patch that converts baseline X to target Y (X â Y).
- Download patch: device downloads the delta payload, typically much smaller than full image.
- Reconstruction: device applies the patch to the baseline image (or a copy) to produce the new image bytes.
- Verify and boot: same authenticity and integrity requirements as full OTA.
Key nuance: âdeltaâ is not always âbinary diff on the whole firmwareâ. You can implement deltas at different layers:
- Binary image delta: diff the entire firmware image bytes.
- Component delta: update only certain modules (for example, an app layer on top of an RTOS, web assets or ML models).
- Block delta: patch only changed flash blocks, common in update frameworks that manage partitions.
Bandwidth, time and cost modeling
Use simple math to make the decision less emotional. Define:
- S = full image size (bytes)
- D = delta size (bytes)
- R = effective throughput (bytes/sec), after protocol overhead and retransmissions
- P_fail = probability of update failure (power loss, link drop, timeout) during the download+install window
Download time
T_full â S / R
T_delta â D / R + T_apply
Delta wins on time when D is much smaller than S and patch application time (T_apply) is small relative to download time.
Fleet bandwidth cost
For N devices updating once:
Data_full = N Ă S
Data_delta = N Ă D
If you pay for cellular data or satellite, this quickly dominates. On the other hand, on Wi-Fi or Ethernet it might not matter, so simplicity may dominate.
Failure risk window
Many failures correlate with time spent âin update modeâ. A longer download and install window increases exposure to power loss and watchdog resets.
- Full updates can have long download windows.
- Delta updates can have additional compute and flash write windows (patch application) even if the download is short.
A practical rule of thumb
- If your typical delta is < 30% of full image size and you can reliably identify the baseline, delta is often worth it.
- If your devices have unknown drift (field repairs, partial updates, different optional features) then full OTA is often safer.
Flash layout, bootloader and rollback implications
Your bootloader and flash partitioning often decides what is feasible. The main patterns are:
A/B (dual-slot) with full image
- Pros: best rollback story, simplest validation model, easy to resume download to inactive slot.
- Cons: requires ~2x firmware storage plus metadata.
Single-slot with staging
- Pros: less flash required than A/B.
- Cons: more complex and riskier, you must avoid bricking during overwrite, often needs external flash or a reliable staging area.
Delta with A/B
- Pros: you can apply patch to build the new image in the inactive slot, then verify and swap like full OTA.
- Cons: you still need the inactive slot space, delta primarily saves bandwidth not flash.
Delta with single-slot (advanced)
- Pros: can reduce bandwidth and keep minimal flash.
- Cons: hardest to do safely. You need careful block-level journaling, power-fail safe patching or an external staging medium.
Practical guidance: If you cannot afford A/B slots in internal flash, consider adding external QSPI flash for staging, or choose full OTA but update a smaller âapplicationâ partition rather than a monolithic image.
Reliability, failure modes and resume
Both approaches must handle the same real-world problems: dead batteries, brownouts, network drops and corrupted storage. The difference is how many âmoving partsâ you add.
Common failure modes for full OTA
- Interrupted download: fix with HTTP Range requests or chunked transfer, plus checkpointing.
- Corrupt image: fix with per-chunk hashes and final image hash.
- Bad boot: fix with A/B and boot attempt counters.
Common failure modes for delta OTA
- Wrong baseline: device thinks it is on X but bytes differ, patch fails or worse, produces a wrong image. Fix with baseline hash, not only version numbers.
- Patch apply interruption: fix with applying into inactive slot, or transactional patching with checkpoints.
- CPU/RAM constraints: some patch algorithms need RAM buffers. Fix by choosing streaming-friendly patch formats.
Resume complexity
Full OTA resume often only needs âcontinue downloading from offsetâ. Delta OTA needs that plus âresume patch apply safelyâ if patching is not atomic.
Security and compliance considerations
Security requirements are similar for both approaches, but delta updates add extra pitfalls.
Minimum security requirements
- Transport security: TLS for HTTP or MQTT over TLS, or OSCORE (Object Security for Constrained RESTful Environments) for CoAP.
- Authenticity: sign update artifacts (full image or delta) using an asymmetric signature (for example, Ed25519 or ECDSA (Elliptic Curve Digital Signature Algorithm)).
- Integrity: verify cryptographic hashes for the final reconstructed image, not only the downloaded artifact.
- Anti-rollback: prevent downgrades unless explicitly allowed, using monotonic counters or version fuses.
Delta-specific security concerns
- Patch correctness: attackers could attempt to craft a patch that triggers buffer overruns in your patch applier. Treat patch input as untrusted and fuzz test your patching code.
- Reconstructed image verification: always verify a signature on the final image bytes (or verify a signed manifest that includes the final image hash). Do not trust âdelta verifiedâ as equivalent to âimage verifiedâ.
- Baseline binding: bind the patch to a baseline hash (for example, SHA-256 of current slot) to prevent applying a patch to the wrong bytes.
Code example 1: Generate and apply delta patches
This example uses bsdiff/bspatch to generate a compact binary diff and apply it. This is a common pattern for delta OTA pipelines: your CI system produces a full image, then produces a delta against the previous release used by most of your fleet.
Step 1: Build two firmware images
You need two binaries: firmware_old.bin and firmware_new.bin. These could be raw images, UF2, Intel HEX converted to raw or a partition image. Delta works best when images are stable between builds, so avoid embedding build timestamps inside the binary if you can.
Step 2: Generate a patch (server or CI)
# Generates a delta patch using bsdiff (run this in CI or on your build server) # Input: firmware_old.bin, firmware_new.bin # Output: firmware_old_to_new.patch set -euo pipefail # Install tools (Ubuntu/Debian) # sudo apt-get update && sudo apt-get install -y bsdiff bsdiff firmware_old.bin firmware_new.bin firmware_old_to_new.patch # Show sizes for a quick sanity check ls -lh firmware_old.bin firmware_new.bin firmware_old_to_new.patch
Step 3: Apply the patch (device-side simulation)
On an embedded device you would run a patch applier as part of your update agent. Here is how to validate the pipeline locally:
# Applies a delta patch using bspatch # Input: firmware_old.bin, firmware_old_to_new.patch # Output: reconstructed_new.bin (should match firmware_new.bin) set -euo pipefail # Install tools (Ubuntu/Debian) # sudo apt-get update && sudo apt-get install -y bsdiff bspatch firmware_old.bin reconstructed_new.bin firmware_old_to_new.patch # Verify reconstructed image matches the intended target sha256sum firmware_new.bin reconstructed_new.bin cmp -s firmware_new.bin reconstructed_new.bin && echo "Patch OK: images match"
How to map this to a real device:
- Store the old image in Slot A, download the patch, reconstruct the new image into Slot B.
- Compute SHA-256 of Slot B and verify it matches a signed manifest.
- Swap boot to Slot B and commit after health checks.
When bsdiff is a poor fit: very constrained microcontrollers sometimes cannot afford the RAM or CPU for bspatch. In that case, use an update framework that supports streaming patch formats or do component-level updates (only patch a file system asset partition).
Code example 2: Resumable full firmware download with integrity
This example shows a practical full-image OTA downloader that supports resume via HTTP Range requests and verifies a final SHA-256. You can run it on a gateway, Linux-based device or as a reference implementation for your embedded update agent.
Step 1: Download with resume
# Resumable firmware downloader with SHA-256 verification
# Usage:
# python3 ota_download.py https://example.com/fw.bin fw.bin <expected_sha256_hex>
import hashlib
import os
import sys
import requests
CHUNK = 1024 * 256
def sha256_file(path: str) -> str:
h = hashlib.sha256()
with open(path, "rb") as f:
for b in iter(lambda: f.read(1024 * 1024), b""):
h.update(b)
return h.hexdigest()
def download_resume(url: str, out_path: str) -> None:
existing = os.path.getsize(out_path) if os.path.exists(out_path) else 0
headers = {"Range": f"bytes={existing}-"} if existing else {}
with requests.get(url, stream=True, headers=headers, timeout=30) as r:
if r.status_code not in (200, 206):
raise RuntimeError(f"HTTP {r.status_code}")
mode = "ab" if existing and r.status_code == 206 else "wb"
with open(out_path, mode) as f:
for chunk in r.iter_content(chunk_size=CHUNK):
if chunk:
f.write(chunk)
def main():
if len(sys.argv) != 4:
print("Usage: python3 ota_download.py <url> <out_file> <expected_sha256>")
sys.exit(2)
url, out_path, expected = sys.argv[1], sys.argv[2], sys.argv[3].lower()
download_resume(url, out_path)
actual = sha256_file(out_path)
if actual != expected:
raise SystemExit(f"SHA mismatch: expected {expected}, got {actual}")
print("Download OK and SHA-256 verified")
if __name__ == "__main__":
main()
Step 2: Device-side mapping
- Resume state: store the current downloaded size in a small metadata region, or infer it from the staging file size or slot write pointer.
- Per-chunk hashes (recommended): store a manifest with chunk hashes to detect corruption early, especially on flaky links.
- Signature verification: verify a signed manifest that includes the expected SHA-256 and version before swapping.
Platform and protocol fit (MQTT, HTTP, CoAP)
Protocol choice is often independent of delta vs full, but some combinations are easier to implement.
HTTP(S)
- Full OTA: excellent fit, supports Range requests, caching, CDNs and straightforward scaling.
- Delta OTA: also good, you download a patch artifact, same tooling as full images.
MQTT
- Full OTA: you typically do not stream multi-megabyte binaries through MQTT brokers unless you control the full path and accept the cost. A common pattern is MQTT for signaling and HTTP for bulk download.
- Delta OTA: same pattern, MQTT tells the device which patch URL to fetch.
CoAP
- Full OTA: can work well in constrained networks, block-wise transfer helps, but tooling is less standardized than HTTP.
- Delta OTA: feasible, but you must be more careful about patch-apply complexity on constrained nodes.
Decision matrix: what to choose
| Criteria | Delta firmware OTA | Full firmware OTA |
|---|---|---|
| Bandwidth usage | Best when changes are small, often 5 to 30% of full | Worst, always 100% of image |
| Implementation complexity | Higher: patch selection, baseline binding, patch apply safety | Lower: download, verify, swap, rollback |
| Reliability across unknown device states | Lower unless you strictly control baselines and drift | Higher: fewer assumptions about current bytes |
| Flash requirements | Often similar to full if you still use A/B slots | High with A/B, medium with staging, lowest with risky in-place |
| CPU and RAM requirements | Can be significant depending on patch algorithm | Typically lower and predictable |
| Security surface | Larger: patch parser and apply logic needs hardening | Smaller: mostly download and signature verification |
| Best for | Cellular fleets, satellite links, very large images, frequent small releases | Early-stage products, heterogeneous fleets, high reliability requirements |
Practical recommendations
1) Start with full A/B OTA unless bandwidth is a top constraint
Full-image A/B updates are the simplest path to a robust updater: atomic swap, simple rollback and easy post-boot commit logic. If you are still stabilizing your product, this reduces the number of hard-to-debug âfield-onlyâ failures.
2) Add delta OTA when you have stable baselines and clear fleet version distribution
Delta starts paying for itself when most devices sit on a small set of known versions. Then your server can host a small number of patches, such as N-1 â N, and get most of the bandwidth savings without combinatorial patch explosion.
3) Avoid patch explosion with a patch policy
- Adjacent-only patches: only generate patches from the previous release to the next (N-1 â N). Devices older than N-1 receive a full image.
- Hub-and-spoke: pick a common baseline version B, generate patches B â target for a period, force older devices to update to B via full once.
4) Bind patches to immutable identifiers
In OTA update strategies: Delta vs Full firmware decisions, the most common delta failure is âwrong baselineâ. Use a cryptographic hash of the current slot (or a build ID embedded in a signed manifest) to select patches safely.
5) Always verify the final reconstructed image
Even if your patch is signed, verify a signature or hash for the final image bytes that you will boot. This keeps your trust model consistent between delta and full OTA.
6) Measure real delta sizes before committing
Delta size depends heavily on how deterministic your builds are. If your build process injects timestamps, random IDs or reorders sections, your deltas may be large. Before you implement delta OTA in production, run a short experiment across 5 to 10 consecutive builds and record D/S ratios.
7) Use progressive rollout and health signals
Regardless of the approach, use staged deployments: update 1% of the fleet, then 10%, then 100% based on crash reports, boot confirmation rates and application-level health checks. This matters more than the delta vs full decision for overall fleet stability.
8) Combine strategies when it makes sense
You do not have to choose only one. Many successful systems use:
- Full OTA for major releases and recovery
- Delta OTA for frequent minor releases
- Component updates for large data assets (web UI, certificates, ML models)
That hybrid approach often gives you the best tradeoff in OTA update strategies: Delta vs Full firmware planning without pushing complexity into every update.
Conclusion
OTA update strategies: Delta vs Full firmware is a trade between bandwidth and complexity. Full image OTA (ideally A/B) maximizes reliability and simplifies rollback, while delta OTA can dramatically reduce data usage when you control baselines and harden patch application. In practice, start with full OTA for robustness, then add delta for high-cost networks or high-frequency releases once you have stable versioning, signed manifests and a clear rollback plan.