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 an owner-only socket file and an owner-only parent directory 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 as the core protocol. mxr now also ships a loopback HTTP/WebSocket bridge because it has a real browser client. That did not replace the Unix socket; it wrapped it. The bridge carries its own security work: bearer auth, Host/CORS defenses, security headers, and auth-gated OpenAPI/Swagger routes.

That is the durable lesson: add HTTP when a browser actually needs it, keep the local IPC as the core, and make the bridge own HTTP-specific concerns instead of leaking them into the daemon protocol.

See also