NEW: The Edge Autonomy Gap report. AI is arriving at the edge — 500 practitioners say the infrastructure isn't ready.
All posts

The short answer

DDIL environments — Denied, Disrupted, Intermittent, and Limited-bandwidth — are networks you cannot assume will be there: tactical edge, maritime, satellite-backhauled remote sites, mobile fleets, and disaster zones. DDIL is usually treated as a connectivity problem, but it is better understood as an autonomous operations problem: the unreliable link is the environment, and autonomous operation is the design response.

Most messaging systems assume a reliable network and degrade badly when it isn’t. NATS is built the other way around, and the reason is the leaf node: a full NATS server that runs as a single ~15–20 MB dependency-free binary on constrained hardware at the edge. When its uplink to the command hub or cloud is severed, the leaf keeps operating locally — local publish/subscribe, request/reply, key-value, and JetStream persistence all keep working offline.

When the link returns, store-and-forward flushes buffered messages in both directions and the topology self-heals. A leaf node is also a security and bandwidth boundary: you fence which subjects and how much interest cross the constrained link, compress every leaf connection, and address an individual device on demand instead of streaming everything down. Local autonomy, store-and-forward resync, per-link subject fencing, and a tiny footprint are what make NATS well suited to DDIL — together they support autonomous operations, not just intermittent connectivity.

What does DDIL stand for, and where does it show up?

DDIL stands for Denied, Disrupted, Intermittent, and Limited-bandwidth — a term that originates in U.S. defense and tactical communications to describe networks operators cannot rely on. A common variant substitutes Degraded for the second D; the two forms are used interchangeably in the wild.

The letters break down as:

  • Denied — the link is actively blocked, jammed, firewalled, or unroutable.
  • Disrupted — the link fails, flaps, or loses a hub without warning.
  • Intermittent — connectivity comes and goes on a duty cycle (a satellite pass, a convoy moving in and out of coverage, a ship over the horizon).
  • Limited-bandwidth — the link exists but is expensive, narrow, or contended (an L-band satellite backhaul, an LTE modem shared across a site, a mesh radio).

DDIL was coined for tactical networks, but the shape shows up anywhere the network is contested, costly, or physically constrained:

  • Defense and tactical edge — forward-deployed teams, vehicles, UAVs.
  • Maritime — ships operating over satellite for days at a time.
  • Satellite and space — LEO/GEO-backhauled remote infrastructure, and payloads on the satellites themselves.
  • Remote industrial — mining, oil and gas, utilities, wind farms, offshore platforms.
  • Mobile fleets and robotics — trucks, trains, autonomous ground and aerial vehicles.
  • Disaster response — pop-up sites where the local network is what you brought with you.

Most systems are designed to operate one way; a DDIL system has to operate two ways — connected to the wider network, and autonomous when the link is gone — and transition cleanly between them. The question DDIL forces on an architect is simple: when the link goes away, does the system keep doing useful work, and does it reconcile cleanly when the link comes back?

Why do most messaging systems struggle in DDIL?

Most messaging systems were designed for a data center, then stretched toward the edge. That has three consequences in DDIL.

They assume a central broker is reachable. A client that cannot reach the broker cannot publish, subscribe, or serve requests. A site whose uplink is severed effectively goes dark, even if all the producers and consumers on that site are sitting next to each other on the same LAN.

They assume consumers can pull whole streams. Log-oriented systems shine when a consumer can read a partition end-to-end. On a bandwidth-starved link, pulling a whole topic to extract the handful of messages a particular vehicle needs is exactly the wrong shape.

Their runtimes are too heavy for the edge. JVMs, ZooKeeper/Raft ensembles, and multi-gigabyte container images are hard to justify on a Raspberry Pi bolted to a vehicle or a small industrial box in a cabinet.

Be fair about what the alternatives are good at. MQTT is the right protocol at the device edge — it is small, well-understood, and ubiquitous on constrained hardware and sensor gateways. Kafka is the right system for high-throughput, append-only log processing in the data center. Neither was designed to keep a remote site autonomous through a denied uplink, and that is the specific job DDIL asks a messaging layer to do.

What is a NATS leaf node?

A leaf node is a full NATS server that runs at the edge and connects outward to a hub cluster over a single, credentialed, long-lived link. The relationship is deliberately asymmetric: the leaf is the initiator, the hub is the anchor, and the connection carries only the subjects and interest the operator explicitly permits.

Three properties matter for DDIL:

  1. It is a full server, not a client shim. Local clients on the leaf talk to a real NATS server. Publish/subscribe, request/reply, JetStream streams and consumers, and the key-value and object stores all work locally, whether or not the uplink is up.
  2. It links accounts. A leaf connection binds one NATS account on the leaf to one on the hub, with imports and exports controlling which subjects cross. The leaf is therefore both a connectivity primitive and a security boundary.
  3. It runs where you need it. The NATS server is a single dependency-free binary in the ~15–20 MB range, so a leaf runs on a Raspberry Pi, an embedded Linux board, a vehicle compute module, or a small VM on a ship. See the leaf node documentation for the wire-level specifics.

Everything that follows is a property of the leaf node. If you keep that primitive in mind, the rest of the architecture is straightforward.

Think of a leaf the way the local-first movement thinks of an application: the network is an enhancement, not a prerequisite. When the uplink goes away, the leaf keeps serving its local clients.

Concretely, with the uplink down, the leaf continues to provide:

  • Local publish/subscribe across all subjects that live on the leaf.
  • Local request/reply between services co-located on the leaf.
  • The key-value and object stores backed by JetStream on the leaf.
  • JetStream streams and consumers whose subjects and storage are local.

The mechanism that makes this safe is a per-leaf JetStream domain. A domain gives the leaf its own independent JetStream namespace and its own Raft groups for stream and consumer replication. Edge consensus never waits on a WAN quorum, because the WAN is not part of the quorum. When the hub is unreachable, the leaf’s own streams keep committing writes; when the hub returns, the two domains reconcile through explicit mirrors and sources rather than a shared cluster. The JetStream documentation covers domains in detail.

The honest caveat. Local autonomy means a leaf keeps serving its own clients and buffers for later resync. It does not mean traffic magically reroutes around a severed hub link to reach other leaves. If leaf A and leaf B normally talk through the hub and the hub link at A is cut, A’s clients keep working, but A cannot reach B until the link returns. If you need east-west traffic between edges to survive independently of the hub, design an explicit path (a direct leaf-to-leaf link, or a regional intermediate hub) rather than assuming the fabric will invent one.

How does NATS handle Intermittent connectivity and reconnection?

Intermittent connectivity is the common case in DDIL — the link comes and goes on a duty cycle. Three properties matter here.

Discovery and gossip. A leaf configured with multiple hub endpoints reconnects to whichever hub server is still up. Cluster membership propagates by gossip, so a leaf that reconnects after a long outage learns the current hub topology without operator intervention.

Store-and-forward on reconnect. JetStream stream mirrors and sources are the primary store-and-forward tool between a leaf and the hub. Messages produced locally into a stream while the uplink was down are pulled up by the hub’s source when the link returns; messages the hub wants to deliver down to the leaf ride the leaf’s mirror. Give each leaf’s consumer a unique name so mirrors and sources from many leaves do not collide.

Interest re-propagation and the churn caveat. When a leaf reconnects, its local subscriptions are re-advertised to the hub as interest. That is cheap for one leaf; it is not free for a fleet. If 50,000 devices reconnect at once — a satellite pass ends, a substation comes back online, an outage clears — that is 50,000 interest re-adds hitting the hub in a short window. Architect for it: stagger reconnects, tune ping intervals and lame-duck behavior at the hub, and keep per-leaf subject cardinality bounded by fencing (next section) rather than letting every device advertise its full local subject tree upstream.

Store-and-forward, in sequence

  1. Uplink is healthy; the leaf mirrors relevant hub streams down and sources local streams up.
  2. Uplink fails. Local producers keep publishing into JetStream on the leaf. Hub producers keep publishing into JetStream on the hub. Both sides buffer according to their stream retention.
  3. Uplink returns. Mirrors and sources resume from their last acknowledged sequence and flush the backlog in both directions.
  4. Topology self-heals via gossip; interest is re-advertised; normal operation resumes.

How does NATS conserve Limited bandwidth?

Limited-bandwidth is the letter operators feel every month on the invoice. NATS gives you four levers.

Compression on the link. Leaf connections (and routes) support S2/Snappy compression, so every byte crossing the constrained uplink is compressed by default when you enable it. This is a config knob, not a rewrite.

Subject and interest fencing. Accounts, imports, exports, permissions, and deny_imports / deny_exports let you specify exactly which subjects cross the leaf link and in which direction. High-cardinality edge interest — per-device telemetry subjects, ephemeral request inboxes, internal service chatter — stays on the leaf and never propagates upstream. Only the subjects you explicitly allow reach the hub.

Inbox muxing. Request/reply generates unique reply subjects. NATS clients multiplex replies over a shared inbox subscription, so a burst of concurrent requests over a leaf link does not translate into a burst of interest updates.

Command-and-control addressability. This is the differentiator worth stressing. Collecting telemetry up is easy for many systems; addressing one device down over a bandwidth-starved link is where NATS is distinctive. Instead of continuously streaming a topic down to a fleet, use core request/reply — or the JetStream republish + direct-get pattern — to fetch or command the exact device you care about, on demand, over a single fenced subject. You can address millions of devices without shipping millions of messages.

How does NATS get through Denied or firewalled networks?

Leaf connections are asymmetric, which turns out to matter more than it sounds. The leaf initiates the TCP connection to the hub, so a leaf sitting behind a NAT or an outbound-only firewall — the common shape at a remote site — can reach a hub with a public endpoint without any inbound rule. If the firewall is the other way around (the hub is deep in a private network and the leaf is on the open side), you can invert the relationship. Either direction can be the initiator.

When a single hop is not enough, leaves daisy-chain: a leaf can itself accept leaf connections from further-edge leaves, so you can relay from deep edge through an intermediate aggregation node up to a central hub. Keep the topology a tree — no cycles — and you have a multi-hop path from the contested edge to the cloud that respects whichever direction each firewall faces.

How do you secure a contested edge?

The leaf is a security boundary as well as a connectivity primitive.

  • Different security postures at different layers. Devices on a leaf may authenticate with lightweight credentials — or, on truly constrained hardware, with none, if the LAN itself is the trust boundary. The uplink is where you apply strict, centralized authentication. Auth Callout lets you plug an external identity system into the NATS auth flow so credentials at the hub can be issued, rotated, and revoked centrally.
  • Per-leaf security models. Because a leaf is a full server, it can enforce its own accounts and permissions independent of the hub.
  • Directional system-account bridging. You can arrange system-account visibility so the hub observes leaves (for monitoring) without leaves observing the hub or each other.
  • Data-locality fencing. Subject imports and exports keep a region’s streams inside that region unless you explicitly export them upward.

A minimal leaf configuration

A short, illustrative leaf configuration — a remote leaf that connects to a hub, runs its own JetStream domain, and refuses to export a sensitive local subject upstream. Applies to NATS Server 2.x; confirm option names against the docs for your exact version.

1
server_name: edge-site-07
2
3
jetstream {
4
store_dir: /var/lib/nats/js
5
domain: edge07
6
}
7
8
leafnodes {
9
remotes = [
10
{
11
url: "nats-leaf://hub.example.internal:7422"
12
credentials: "/etc/nats/edge07.creds"
13
compression: s2_auto
14
}
15
]
16
}
17
18
accounts {
19
EDGE: {
20
users: [ { user: "local", password: "..." } ]
21
exports: [
22
{ stream: "telemetry.>" }
23
]
24
# Sensitive local subjects never cross the uplink.
25
# Combine with hub-side import rules for defense in depth.
26
}
27
}

On the hub side, the matching account imports telemetry.> and nothing else. The uplink carries compressed traffic, the leaf has its own JetStream domain (edge07), and any subject not explicitly exported stays on the leaf.

With the uplink to the hub severed, a NATS leaf node continues to serve:

  • Local publish/subscribe on all local subjects
  • Local request/reply between services on the leaf
  • The key-value and object stores
  • JetStream streams and consumers in the leaf’s domain
  • MQTT 3.1.1 clients connected to the leaf’s MQTT listener

Messages produced locally are buffered by JetStream retention and flushed to the hub via stream mirror/source when the link returns.

Capability map: DDIL requirement → NATS capability

DDIL requirementNATS / leaf-node capabilityHow it helps
Operate when the uplink is DeniedLeaf-node local autonomyLocal pub/sub, request/reply, KV, and JetStream keep serving with no hub dependency
Survive a Disrupted hub/outageIndependent Raft groups + a per-leaf JetStream domainEdge cluster stays consistent on its own; no global-quorum dependency over the WAN
Re-sync after Intermittent reconnectStore-and-forward via stream mirror/source (unique per-leaf consumer names)Buffered messages flush in both directions when the link returns
Self-heal the topologyServer discovery/gossipLeaves reconnect to surviving hub nodes automatically
Conserve Limited bandwidthS2/Snappy compression on leaf and route linksEvery byte over the constrained link is compressed
Avoid flooding the linkSubject + interest fencing (permissions, deny_imports/deny_exports)Only chosen subjects and interest cross; high-cardinality edge interest stays local
Address one device, not the fleetCore request/reply + republish/direct-getCommand a single device on demand without streaming everything down
Run on constrained hardwareA single ~15–20 MB dependency-free binaryRuns on a Raspberry Pi or embedded Linux at the edge
Traverse denied/firewalled networksAsymmetric leaf connections + daisy-chainingConnect in whichever direction the firewall allows; multi-hop relay
Secure the contested edgeLeaf as a security boundary; centralized Auth CalloutLoose posture at the edge, strict on the uplink; per-leaf security models
Carry existing device protocolsNative MQTT 3.1.1 listener on the leafSparkplug and other MQTT payloads ride the same fabric

A note on protocols: NATS carries MQTT 3.1.1 traffic natively through the built-in MQTT server; it does not interpret Sparkplug or other MQTT payloads, it transports them. Existing device fleets keep speaking MQTT; the leaf gives that MQTT traffic the DDIL properties described above.

FAQ

What does DDIL stand for? DDIL stands for Denied, Disrupted, Intermittent, and Limited-bandwidth. A common variant uses Degraded in place of the second D. It originates in defense and tactical communications and describes networks operators cannot assume are always available.

What is a DDIL environment? Any environment where the network is contested, unreliable, or expensive: tactical edge, maritime, satellite backhaul, remote industrial sites, mobile fleets, and disaster response. The defining question is whether the system keeps doing useful work when the link is down and reconciles cleanly when it returns.

What is the best messaging system for DDIL environments? A messaging system suited to DDIL must operate locally without a central broker, buffer and re-sync automatically on reconnect, run on constrained hardware, and let operators fence which subjects and how much traffic cross the constrained link. NATS is designed around those properties, with the leaf node as the load-bearing primitive. It also runs the same technology at the edge and the hub, so autonomous operation is a built-in pattern rather than a pile of custom bridges and failover glue.

Can NATS work offline / without a connection? Yes. A NATS leaf node is a full server, so clients connected to a leaf continue to publish, subscribe, issue requests, and read and write JetStream, key-value, and object stores while the uplink to the hub is down. The leaf buffers messages according to JetStream retention and flushes them on reconnect.

What are NATS leaf nodes? A leaf node is a full NATS server that connects outward to a hub cluster over a single credentialed link. It links one account on the leaf to one on the hub, exposes only the subjects the operator permits to cross, and runs as a single small binary on constrained hardware.

How does NATS handle intermittent connectivity? Leaf connections reconnect automatically to surviving hub servers via discovery and gossip. JetStream stream mirrors and sources implement store-and-forward in both directions, flushing buffered messages when the link returns. For large fleets, architect for interest re-propagation churn by staggering reconnects and bounding per-leaf subject cardinality with fencing.

How does NATS work in disconnected environments? Each leaf runs a per-leaf JetStream domain with its own Raft groups, so edge consensus is independent of any WAN quorum. Local traffic on a disconnected leaf keeps working; cross-edge traffic that normally traverses the hub does not reach other leaves until the link returns. Design explicit paths if east-west edge traffic must survive hub loss.

Go deeper


Want help from the NATS experts? Meet with our architects to get help tailored to your use case and environment.

Get the NATS Newsletter

News and content from across the community


Cancel