Digital twins are one of those concepts that sound more complicated than they are. At the core, a digital twin is just a software representation of a physical device — a data structure that reflects the device’s current state and gives applications a single point of contact for reading from and writing to that device. The value is in the abstraction: applications don’t need to know whether the device is currently connected, what protocol it speaks, or where it is on the network. They ask the twin.

Eclipse Ditto is an open-source implementation of this pattern, built by the Eclipse Foundation and originally developed at Bosch. It’s mature, it runs on Kubernetes, and it integrates with the messaging infrastructure most IoT deployments already use. Here’s how it works and where it fits in an edge or industrial IoT architecture.

The Core Model: Things and Features

In Ditto’s model, a physical device is represented as a Thing. A Thing has a thingId (a namespaced identifier like org.example:temperature-sensor-001) and one or more Features — collections of named properties that describe the device’s state.

{
  "thingId": "org.example:temperature-sensor-001",
  "features": {
    "temperature": {
      "properties": {
        "current": 23.4,
        "unit": "celsius",
        "timestamp": "2026-06-18T09:15:00Z"
      }
    },
    "battery": {
      "properties": {
        "level": 87,
        "charging": false
      }
    }
  }
}

Applications interact with this object through Ditto’s HTTP API or WebSocket API. A GET request to /api/2/things/org.example:temperature-sensor-001/features/temperature/properties/current returns the current temperature reading. The application doesn’t know whether that reading came in over MQTT five minutes ago or thirty seconds ago — it just gets the last-known state.

Live vs. Stored State

Ditto handles two distinct modes: stored state and live messages. Stored state is the last-known snapshot of the device’s properties — what the twin holds in its database. Live messages are real-time commands sent to the device directly, routed through Ditto as a protocol-agnostic broker.

The distinction is important for IoT architectures. You might read temperature from stored state (you just want to know what the sensor reported last, and it updates every 60 seconds anyway). But you’d send an actuator command — “open valve”, “set setpoint to 20°C” — as a live message, because you need the device to respond right now.

Ditto supports live messaging through its existing connectivity channels. If your device is reachable over MQTT, Ditto forwards the live message to the MQTT broker and waits for a response. The application sees a synchronous-ish API even though the underlying communication is async.

Connectivity: How Devices Feed the Twin

Ditto doesn’t talk directly to devices. It sits above your existing messaging infrastructure and consumes device data from it. You configure connections in Ditto that tell it where to listen for device state updates — an MQTT broker, an AMQP server, Apache Kafka, or HTTP webhooks.

A typical setup looks like this:

  1. Devices publish their telemetry to an MQTT broker (Mosquitto, HiveMQ, EMQX)
  2. Eclipse Hono (an IoT connectivity layer often paired with Ditto) handles device authentication and protocol normalisation
  3. Hono forwards telemetry messages to Kafka
  4. Ditto consumes from Kafka, maps the messages to Thing updates using a JavaScript transformation function, and updates the stored state
  5. Applications query Ditto’s API to read device state

The JavaScript mapping functions are Ditto’s most flexible feature and its steepest learning curve. They let you transform arbitrary incoming message formats into Ditto’s internal model. A device that sends {"t":23.4,"b":87} can be mapped to update the temperature.current and battery.level properties correctly without changing anything on the device.

Policy-Based Access Control

Every Thing in Ditto has a Policy attached to it — an access control configuration that specifies who can read or write different parts of the Thing. Policies are themselves first-class resources that can be shared across multiple Things.

{
  "policyId": "org.example:sensor-read-policy",
  "entries": {
    "owners": {
      "subjects": {
        "nginx:owner-service": { "type": "nginx" }
      },
      "resources": {
        "thing:/": { "grant": ["READ", "WRITE"], "revoke": [] }
      }
    },
    "consumers": {
      "subjects": {
        "nginx:analytics-service": { "type": "nginx" }
      },
      "resources": {
        "thing:/features/temperature": { "grant": ["READ"], "revoke": [] }
      }
    }
  }
}

The analytics service can read temperature data. It can’t write to the device or see battery state. Fine-grained access control at the feature level lets you build multi-tenant IoT platforms where different applications or teams see only what they’re supposed to see.

When Ditto Makes Sense

Ditto is well-suited to deployments where multiple applications need to read device state, where you want a protocol-independent abstraction layer, or where you need to expose IoT data as a clean API to downstream systems.

It’s particularly useful in industrial IoT and building management systems where devices are operated by different teams with different data access rights, and where the physical hardware comes from multiple vendors using different protocols and data formats. Ditto’s mapping layer normalises all of that behind a consistent API.

It’s less suited to pure streaming scenarios where you need every raw sensor reading in order without buffering. If you’re building a time-series analytics pipeline that needs every data point, connect directly to your Kafka stream rather than routing through Ditto. Ditto stores state, not history.

Deployment

Ditto runs as a set of Java microservices — connectivity, things, policies, search — behind a Gateway service that exposes the APIs. The recommended deployment is Kubernetes. The project publishes Helm charts and Docker images.

Minimum viable deployment for development is two to four CPU cores and 4GB RAM. Production deployments scale horizontally; the services are stateless apart from the Things and Policies stored in MongoDB. For edge deployments on constrained hardware, Ditto’s resource requirements are a real consideration — it’s not a microcontroller-class system. It belongs on an edge server or gateway with proper compute, not on the devices themselves.

Eclipse Ditto is actively maintained, supports the WoT (Web of Things) standard for Thing Description schemas, and integrates with the broader Eclipse IoT ecosystem including Eclipse Hono and Eclipse Hawkbit for OTA updates. For teams building multi-device IoT platforms who want an open alternative to proprietary twin services from AWS or Azure, it’s the most mature option available.