IoT systems fail in production for reasons that never appear in a prototype: a firmware update that bricks a device with no rollback path, a telemetry interval that drains a battery in three weeks instead of three years, a cloud dependency that turns a network outage into a completely non-functional product. None of these show up when you're demoing ten units on a desk. All of them show up at fleet scale.

The four-layer stack

Every IoT system, regardless of application, is made of the same four layers. Getting each one right independently matters more than any single clever architectural choice.

1. Device / firmware layer

Microcontroller selection is a power, cost, and capability tradeoff, not a default choice. An ESP32 gives you Wi-Fi and Bluetooth on-chip and a large hobbyist ecosystem, good for connected consumer devices where Wi-Fi infrastructure is a safe assumption. An STM32 gives you tighter power control, more predictable real-time behavior, and a cleaner path to certification for industrial applications, at the cost of needing separate connectivity hardware. An nRF52/53 series part is the default choice when Bluetooth Low Energy and multi-year coin-cell battery life is the actual requirement. The wrong choice here is expensive to reverse once you're in production, since it usually means a hardware respin.

2. Connectivity layer

The protocol choice depends almost entirely on the range, power, and bandwidth tradeoff your application actually needs, not which protocol is most talked about.

ProtocolRangePowerBandwidthGood fit
MQTT (over Wi-Fi)Local networkModerateHighMains-powered devices, high telemetry rate
BLE~10-30mVery lowLowWearables, phone-paired devices
LoRaWAN2-15kmVery lowVery lowSparse sensors, agriculture, infrastructure monitoring
NB-IoT / LTE-MCellularLow-moderateLowMobile or remote assets with no local gateway
Zigbee~10-100m, meshLowModerateDense sensor/actuator networks in a building

The single most common mistake at this layer is picking Wi-Fi/MQTT by default because it's the most familiar, then discovering the device needs battery life the protocol was never designed to provide.

3. Edge layer

The decision that matters most here: what gets processed on-device versus what gets shipped to the cloud. Sending raw sensor data for every reading is simple to build and expensive to run at scale, both in bandwidth cost and in battery life. Processing on the edge (filtering, aggregating, running lightweight inference locally) cuts bandwidth and power dramatically, at the cost of more complex firmware and a harder update story once logic lives on-device instead of centrally.

The practical rule: anything that needs to react in under a second (a safety interlock, a local alarm) has to live on the edge regardless of cost, because a round trip to the cloud is not a reliable dependency for that use case. Anything that's purely for historical analysis or dashboards can reasonably live in the cloud.

4. Cloud / dashboard layer

This is where telemetry lands, gets stored, and becomes visible: time-series storage, alerting rules, historical analytics, and the operator-facing dashboard. This layer is the most "standard" software engineering of the four, and the layer most similar to conventional backend work, but it still needs to be designed around the actual shape of IoT data: high write volume, mostly time-series, with device identity and fleet grouping as first-class concepts from day one, not bolted on later.

What breaks between 10 devices and 10,000

  • OTA updates without a rollback path. At ten devices, a bad firmware push is an afternoon of re-flashing by hand. At ten thousand, it's a fleet-wide outage, and if there's no automatic rollback on boot failure, it can mean a truck roll to every device in the field.
  • No provisioning story. Manually flashing device certificates and Wi-Fi credentials works for a demo. It does not work for a factory line shipping hundreds of units a day; provisioning needs to be automated and secure from the start.
  • Chatty telemetry. A one-second reporting interval that looked fine on a bench with mains power will drain a battery-powered device in days. Report intervals and payload size need to be budgeted against the actual power source, not left at a debug-friendly default.
  • No offline mode. A device that becomes non-functional the moment it loses connectivity is a fragile product. Critical local behavior (safety logic, core functionality) needs to keep working without the cloud; the cloud connection should degrade the experience, not remove it entirely.
  • Fleet visibility gaps. At small scale, you can SSH into a device to debug it. At fleet scale, you need remote diagnostics, health telemetry, and alerting on device-level anomalies (unusual battery drain, repeated reconnects) before a customer notices something is wrong.

Designing for the fleet from day one

The cheapest time to make these decisions is before the first hardware revision is finalized, because MCU choice, connectivity protocol, and the OTA/provisioning story are all expensive to change after a device is in the field. A prototype that's allowed to skip all of this to prove the core concept quickly is reasonable. A prototype that gets shipped as-is to production, with the fleet-management layer bolted on afterward, is where most IoT programs run into trouble.

The demo proves the sensor works. The architecture proves the product survives contact with ten thousand of them in the field, most of which you'll never physically touch again.