Local IPC vs HTTP

Local IPC vs HTTP

When two processes on the same machine need to communicate, you have two paths: stick local (Unix socket, named pipe, shared memory) or go through HTTP-over-loopback. The local-IPC path is faster, simpler, more secure, and harder to expose accidentally. HTTP is easier to consume from browsers and remote consumers.

This is one of the more important "default-choice" decisions in tool design. Most local daemons should default to local IPC.

The two paths

   Local IPC                              HTTP over loopback
   ─────────                              ──────────────────
   Client process                         Client process
        │                                      │
        │ socket(AF_UNIX, SOCK_STREAM)        │ HTTP client (curl, fetch)
        ▼                                      ▼
   Kernel buffer                          TCP/IP stack
        │                                      │
        ▼                                      ▼
   Daemon process                         loopback (lo) interface
                                                │
                                                ▼
                                          TCP/IP stack
                                                │
                                                ▼
                                          HTTP server (handler dispatch)
                                                │
                                                ▼
                                          Daemon process

HTTP-over-loopback adds two TCP/IP traversals plus HTTP parsing. Local IPC skips both.

Performance

Order-of-magnitude figures (rough, modern hardware, single message):

Mechanism Round-trip latency Throughput (small msgs)
Function call (in-process) ~1ns
Shared memory + lock ~50ns
Unix socket (stream) ~5–10µs 1M+ msgs/sec
TCP loopback ~15–30µs 300K msgs/sec
HTTP over loopback (no keep-alive) ~100–200µs 30K msgs/sec
HTTP over loopback (with keep-alive) ~30–60µs 100K msgs/sec

Per-call latency rarely matters. Throughput at scale does. Most CLI/agent invocations are infrequent enough that even HTTP loopback is fine; for a tool like a language server doing 1000s of completions/sec, local IPC is the right default.

Security

Unix socket security via filesystem permissions:

HTTP-over-loopback security:

For a per-user daemon holding sensitive state (email, debug session with secrets, project state), Unix sockets with 0700 are dramatically safer than HTTP-on-localhost.

Browser accessibility

The single biggest reason to use HTTP-over-loopback: browsers can't open Unix sockets directly. If your daemon needs to be consumed from a web app running in the user's browser, HTTP (or WebSocket) is forced.

Workarounds:

Most "local web UI" tools do the bridge. Some (Jupyter, gitkraken) run web servers directly.

Discoverability

HTTP wins on tooling:

Unix sockets need:

For tools where third parties build clients, HTTP's tooling advantage matters. For tools where the project ships its own clients (mxr, lazydap), local IPC's simplicity wins.

Versioning

Both can be versioned, but conventions differ:

When to use HTTP locally

When to use Unix sockets

What mxr and lazydap do

Both use Unix sockets. Both could (in principle) ship a separate mxr-bridge / lazydap-bridge binary that exposes HTTP-over-loopback for browser consumers. Neither has bothered yet — there's no concrete browser frontend asking for one.

If a future Electron app or web dashboard arrives, the bridge is a one-weekend project on top of the existing protocol. The local IPC stays clean; the bridge handles HTTP-specific concerns (CORS, sessions, etc.).

See also