A common early mistake in IoT platform design is assuming a mobile app or dashboard can just query a device directly for its current state. In practice, most devices are asleep, offline, or on an intermittent connection most of the time — especially battery-powered ones — so a direct query usually times out or returns stale information. A device shadow (also called a digital twin, though that term is used more broadly elsewhere) solves this by maintaining a cloud-side representation of device state that apps interact with instead of the device itself.

What a device shadow actually is

A device shadow is a cloud-stored JSON-like document per device, holding the last known reported state (what the device last told the cloud about itself) and, often, a desired state (what the app or system wants the device to become). Apps read and write to the shadow, not to the device directly. The device, whenever it connects, syncs the shadow — pushing its current reported state and pulling any pending desired-state changes to act on. This decouples app interactions from device connectivity: an app can "set" a device's configuration at any time, and it takes effect the next time the device actually connects, without the app needing to know or care whether the device is online right now.

Reported state vs. desired state

This reported/desired split is what makes the pattern useful for offline devices specifically — a change requested while a device is offline isn't lost or immediately failed, it's queued as part of the desired state and applied on next connection.

Sync conflict handling

Because a device and its cloud shadow can diverge — the device may have changed state locally (a button press, a sensor threshold trigger) between syncs — the sync protocol needs a clear conflict resolution rule. Common approaches include version numbers or timestamps on state changes, with a defined precedence rule (device-reported state usually wins for anything the device controls directly, cloud desired-state wins for remote configuration) applied consistently rather than left ambiguous.

Where this pattern earns its complexity

For very simple products with a single companion app and no fleet-wide management needs, a full shadow architecture can be more infrastructure than the product needs — it's a pattern that earns its complexity at fleet scale or with multi-client access requirements, not a default for every connected product.

How we approach this

We size the shadow/twin architecture to the product's actual connectivity pattern and fleet-management needs, rather than defaulting to it regardless of scale. See our cloud & device platform work for how this fits into a full fleet-management build.