← All Posts

Single Binary vs Microservices: Why SCADA Should Not Be Distributed

Every software architect fresh out of a Silicon Valley bootcamp will tell you the same thing: monoliths are legacy. Microservices are the future. Break your system into small, loosely coupled services. Deploy them in containers. Orchestrate with Kubernetes. Add a service mesh for observability. Scale horizontally.

Now try explaining that to a plant engineer whose job is to keep a boiler from exploding. Their SCADA system runs on a single industrial PC in a dusty cabinet. The network is air-gapped. And when something breaks at 2 AM, they need one log file — not five.

This post is about why single binary deployment is the right industrial software architecture for SCADA, and why microservices vs monolith SCADA is not even a debate in the field. For a broader overview of how components fit together, see our guide to SCADA architecture.

The Comparison

Factor
Microservices Stack
Single Binary
Process Count
5-10 services + sidecars
1 process
RAM Footprint
1-3 GB aggregate
No dedicated server needed
Log Files
5-10 log streams
1 log file
Configuration
5+ config files + env vars
1 YAML file
Restart on Crash
Orchestrator-dependent
systemctl restart
Deployment Tooling
Docker Compose / K8s / Helm
scp + systemd
Network Complexity
Service discovery + mesh
localhost
Update Process
Rolling deploys, version matrices
Replace binary, restart

The Reality of Five Services

Here is what the microservices advocates do not tell you: five services means five things that can break. Not abstractly. Concretely. At 2 AM. In a factory where the night shift does not know what Kubernetes is.

Five Logs to Check

When a sensor stops updating, where is the problem?

  • Is the data acquisition service still polling Modbus?
  • Did the message broker drop the connection?
  • Is the time-series database accepting writes?
  • Did the API gateway route the request correctly?
  • Is the frontend service rendering stale data?

You are now SSH-ing into five containers, running kubectl logs on each, and correlating timestamps across distributed systems. The plant engineer is watching over your shoulder, wondering why monitoring a temperature sensor requires a CS degree.

Five Configs to Maintain

Each service has its own configuration:

  • Broker connection strings
  • Database credentials and retention policies
  • API gateway routing rules
  • Service-to-service auth tokens
  • Frontend build-time environment variables

Change the database password? Update four configs. Rotate a TLS certificate? Hope you remembered which services mount which secrets. Add a new sensor? Edit the acquisition config, the broker topic rules, and the dashboard service's allowed metrics list.

Five Failure Modes

Network partitions between services are not theoretical in industrial environments. They happen when:

  • A network switch reboots during maintenance
  • Someone unplugs the wrong cable
  • The industrial PC runs out of disk space (logs from five services)
  • A service restarts faster than its dependency and fails health checks
  • Clock skew breaks token-based auth between services

A single binary has none of these problems. It is one process. One memory space. One event loop. If it runs, everything works. If it crashes, you see the stack trace in one place.

"But Microservices Scale"

This is the argument that ends every debate. "Sure, a monolith is simpler now. But what happens when you need to scale?"

Scale what, exactly?

The median SCADA deployment monitors fewer than 100 sensors. Each sensor sends a Float32 value every 1-5 seconds. That is 400 bytes per second. Over a day, that is 34 MB of data. Over a year, 12 GB.

You do not need horizontal pod autoscaling for 12 GB per year. You do not need a service mesh to route 100 data points per second. You do not need Kafka to buffer a throughput that fits comfortably in a single TCP connection.

What you do need is reliability at the edge. Industrial deployments run on constrained hardware: ARM-based gateways, old x86 boxes with 2 GB RAM, virtual machines on hypervisors shared with HMI systems. A microservices stack with its 1+ GB RAM baseline is not scaling — it is disqualifying itself from the hardware. This is why lightweight SCADA software that runs on minimal resources is essential for real-world deployments.

Scaling laws for industrial software: If you can handle the load on a Raspberry Pi, you have scaled enough. The goal is not infinite horizontal growth. The goal is predictable behavior on the cheapest hardware that fits in the cabinet. For a real-world example, see our guide on running SCADA on a Raspberry Pi for edge computing.

Deployment Complexity: One Binary vs Everything Else

Let us compare the deployment experience.

Single Binary

  1. Copy file to server
  2. Run chmod +x
  3. Start with systemd

Done. One file. One config. One health check endpoint. One command to restart.

Docker Compose

  1. Install Docker
  2. Write docker-compose.yml
  3. Configure networks and volumes
  4. Manage image versions across services
  5. Handle container restart policies
  6. Debug bind mount permissions

Now you have added a container runtime, a YAML orchestrator, volume management, and image versioning to a system that previously needed one binary. Your attack surface just quadrupled.

Kubernetes

Kubernetes is the industry standard for cloud-native applications. It is also overkill for every SCADA deployment we have ever seen.

  • etcd for state — another database to maintain
  • kubelet + kube-proxy — more processes, more logs
  • Ingress controllers — because now you need HTTP routing inside the plant
  • Helm charts — templating YAML with YAML
  • Service mesh — mTLS between services that should never have been separate

You are now running a mini cloud inside an industrial cabinet. The plant's IT contractor, who knows Windows Server and Siemens PLCs, is expected to troubleshoot this.

Why Distributing SCADA Fails in Practice

Industrial environments are not like cloud data centers. They have specific constraints that make distributed systems a liability:

Air-Gapped Networks

Many plants do not have internet access. Pulling Docker images from a registry is impossible. Updating a Kubernetes cluster requires USB drives and manual steps. A single binary fits on a USB drive and installs without dependencies.

Legacy Hardware

The industrial PC running your SCADA might be ten years old. It has 4 GB RAM and a spinning disk. It cannot run a container runtime without grinding to a halt. A 20 MB native binary starts instantly.

Minimal Local Expertise

The person maintaining the system is often a plant electrician or an instrumentation technician. They are excellent at their job. Their job is not debugging inter-service communication failures. They need a system where broken means the process stopped, and fixed means you started it again.

Long Uptime Requirements

Industrial systems run for years between planned shutdowns. Every additional service is an additional failure mode. Every network hop is a latency source. Every config file is a potential mismatch after an unplanned restart.

The Single Binary Advantage

Voltrus is built as a single binary for a reason. Here is what that means in practice:

  • One process. The data acquisition, storage, API, and dashboard all run in the same memory space. No IPC latency. No serialization overhead. No network hops between components.
  • One log. When something goes wrong, you read one file. Stack traces include the full context. You do not grep across containers.
  • One restart. systemctl restart voltrus brings the entire system back online in under a second. No dependency ordering. No health check cascading.
  • One config. A single YAML file defines devices, polling intervals, retention policies, and user access. Change it, restart, done.
  • No runtime dependencies. No Docker. No JVM. No Node runtime. The binary links against libc and nothing else.

This is not a step backward. It is an architecture choice optimized for the environment it runs in.

When Microservices Actually Make Sense

To be fair, there are cases where distribution is justified:

  • Multi-site aggregation. A central system collecting from 50 plants can benefit from independent ingest services.
  • Mixed technology stacks. If one component must be Python (ML inference) and another Go (high-throughput ingestion), separate processes make sense.
  • Teams larger than ten engineers. Conway's Law is real. If your org structure demands bounded contexts, microservices align with it.

Notice what is missing from that list: a single plant monitoring 40 Modbus sensors. That is the majority of SCADA deployments. And for that majority, distribution adds cost without adding value.

Frequently Asked Questions

Is a single binary architecture better than microservices for SCADA?

Yes, for most SCADA deployments. A single binary eliminates inter-service communication failures, reduces RAM footprint from 1-3 GB to under 100 MB, simplifies deployment to scp + systemctl restart, and produces one log file instead of five. The median SCADA deployment monitors fewer than 100 sensors generating roughly 12 GB of data per year — well within the capacity of a single process.

Why do microservices fail in industrial environments?

Industrial environments have air-gapped networks, legacy hardware with 2-4 GB RAM, and maintenance staff who are plant electricians rather than DevOps engineers. Microservices require container runtimes, service discovery, and orchestration tooling that this hardware cannot support and this staff cannot troubleshoot at 2 AM.

How do you deploy a single binary SCADA system?

Copy the binary to the server via scp or USB drive, run chmod +x, configure a single YAML file with device addresses and polling intervals, and start it with systemd. No Docker, no Kubernetes, no runtime dependencies. Updates are the same process: replace the binary and restart.

Can a single binary handle industrial-scale monitoring?

Yes. A typical SCADA deployment monitors fewer than 100 sensors sending a Float32 value every 1-5 seconds. That is roughly 400 bytes per second, or about 12 GB per year. A single binary written in Rust or Go handles this load on a Raspberry Pi with CPU cycles to spare. Horizontal scaling is only needed when aggregating data across 50+ separate plants.

When should SCADA use microservices instead of a monolith?

Microservices make sense for multi-site aggregation (collecting data from 50+ plants), mixed technology stacks (Python ML inference alongside Go data ingestion), or engineering teams larger than ten people where bounded contexts align with team structure. A single plant monitoring 40 Modbus sensors does not meet any of these thresholds.

One Binary. Zero Bloat.

Voltrus is a single-binary SCADA that runs on a $4 VPS. No containers. No orchestration. Just copy, configure, and run.

See How Voltrus Works

Further Reading