Frigate Inter-Process Communication System: How ZeroMQ Powers Real-Time Video Analytics
Frigate uses ZeroMQ (ØMQ) as its inter-process communication system, implementing a publish/subscribe pattern with a central proxy to route messages between detector workers, the core FastAPI server, WebSocket clients, and optional MQTT bridges.
Frigate is an open-source Network Video Recorder (NVR) with real-time object detection capabilities. To isolate CPU-intensive inference tasks from the web server while maintaining millisecond-level latency, the project implements a sophisticated inter-process communication system based on ZeroMQ sockets that enables asynchronous, non-blocking message passing between distributed components.
Architecture of the ZeroMQ IPC Layer
The communication backbone centers on a lightweight ZeroMQ proxy (frigate/comms/zmq_proxy.py) that brokers PUB/SUB traffic between isolated processes. Each component creates publisher or subscriber sockets using the zmq_ipc helper module (frigate/detectors/plugins/zmq_ipc.py), communicating over ipc:// transport endpoints.
This design decouples the detector workers (running TensorFlow or ONNX inference) from the core application (FastAPI server) and WebSocket broadcaster, preventing Global Interpreter Lock (GIL) contention while ensuring real-time event delivery.
Message Flow Between Components
The IPC system follows a strict message flow that guarantees delivery without blocking the inference pipeline:
-
Detector workers publish detection events – After processing video frames, workers publish detection events, motion clips, and object-track data to a PUB socket connected to
ipc:///tmp/frigate.ipc. -
The proxy routes messages – The central proxy receives messages on its frontend socket and immediately forwards them to its backend socket, acting as a message bus that decouples publishers from subscribers.
-
The core consumes events – The FastAPI server subscribes to the backend socket to update the database, refresh the UI, and push real-time updates to WebSocket clients via
frigate/comms/ws.py. -
External services receive broadcasts – Optional components like the MQTT bridge (
frigate/mqtt/__init__.py) subscribe to the same backend socket to forward Frigate events to Home Assistant or other external systems.
Why Frigate Uses ZeroMQ for IPC
ZeroMQ provides specific advantages that make it ideal for Frigate's distributed architecture:
-
Low latency – The socket implementation is pure C with no heavyweight protocol parsing, enabling detection updates to reach the UI within milliseconds.
-
Scalable communication patterns – Built-in support for PUB/SUB, PUSH/PULL, and REQ/REP patterns allows Frigate to add new consumers (such as external analytics services) without modifying existing publisher code.
-
Transport agnostic – The same codebase works over
ipc://for same-host processes andtcp://for distributed container setups, enabling flexibility in deployment topology. -
GIL isolation – Because ZeroMQ sockets work between independent processes, each detector runs in its own Python interpreter, eliminating GIL contention between CPU-heavy inference and the web server.
Implementation Examples
Publishing Detection Events from Workers
Detector workers use the zmq_ipc helper to publish events via multipart messages with topic filtering:
# frigate/detectors/plugins/zmq_ipc.py
import zmq
import json
ctx = zmq.Context.instance()
pub = ctx.socket(zmq.PUB)
pub.connect("ipc:///tmp/frigate.ipc")
def publish_detection(event: dict) -> None:
"""Send a detection payload to the core."""
payload = json.dumps(event).encode("utf8")
# Topic "events" allows subscribers to filter efficiently
pub.send_multipart([b"events", payload])
Subscribing to Events in the Core
The FastAPI core and WebSocket broadcaster subscribe to the backend socket to receive filtered events:
# frigate/comms/zmq_proxy.py - subscriber pattern
import zmq
ctx = zmq.Context.instance()
sub = ctx.socket(zmq.SUB)
sub.connect("ipc:///tmp/frigate.ipc")
sub.setsockopt(zmq.SUBSCRIBE, b"events")
while True:
topic, payload = sub.recv_multipart()
event = json.loads(payload)
# Process event: store in DB, push to WebSocket, etc.
Starting the ZeroMQ Proxy
The proxy must run continuously to forward messages between frontend (publisher) and backend (subscriber) sockets:
python -m frigate.comms.zmq_proxy \
--frontend="ipc:///tmp/frigate.ipc" \
--backend="ipc:///tmp/frigate.backend.ipc"
The proxy binds the frontend socket where workers publish and the backend socket where the core subscribes, ensuring that late-joining subscribers immediately receive new messages without requiring message persistence or complex queue management.
Key Source Files
The IPC implementation spans several critical files in the blakeblackshear/frigate repository:
frigate/comms/zmq_proxy.py– Central ZeroMQ proxy that routes PUB/SUB traffic between all processes.frigate/detectors/plugins/zmq_ipc.py– Helper module that creates standardized PUB sockets for detector workers.frigate/comms/ws.py– WebSocket broadcaster that subscribes to the backend socket to push browser updates.frigate/mqtt/__init__.py– MQTT bridge that subscribes to the backend to forward events to external home automation systems.
Summary
- Frigate's inter-process communication system relies on ZeroMQ sockets to connect detector workers, the core server, and external services.
- A central proxy (
zmq_proxy.py) routes PUB/SUB messages overipc://transport, preventing GIL contention between inference and web serving. - The PUB/SUB pattern allows multiple consumers (WebSocket, MQTT, database) to receive detection events without impacting the publisher's performance.
- ZeroMQ's transport-agnostic design enables Frigate to scale from single-process deployments to distributed container architectures using the same codebase.
Frequently Asked Questions
What inter-process communication system does Frigate use?
Frigate uses ZeroMQ (ØMQ) as its IPC mechanism, implementing a publish/subscribe pattern with a central message proxy that routes detection events between worker processes and the core application.
Why doesn't Frigate use MQTT for internal IPC?
While Frigate supports MQTT for external integration with home automation platforms, it uses ZeroMQ internally because ZeroMQ provides lower latency, more flexible socket patterns (PUB/SUB vs MQTT's broker model), and operates without requiring a separate broker service for internal process communication.
How does the proxy handle late-joining subscribers?
The ZeroMQ proxy guarantees that any subscriber connecting to the backend socket will immediately start receiving new messages published after the connection is established. This works without message persistence or complex queue management, ensuring the core application can restart without losing the ability to receive fresh detections.
Can Frigate components run on different physical machines?
Yes, because ZeroMQ is transport-agnostic. While the default configuration uses ipc:// sockets for same-host communication, changing the endpoints to tcp:// allows detector workers to run in separate containers or on different machines while using the same proxy architecture and code implementation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →