# What Is the Buzz Relay Architecture? A Technical Deep Dive into block/buzz

> Explore the Buzz relay architecture, a modular Nostr relay implementation supporting NIP-29. Learn about its WebSocket and HTTP APIs for media, Git, and webhooks.

- Repository: [Block Open Source/buzz](https://github.com/block/buzz)
- Tags: deep-dive
- Published: 2026-08-28

---

**The Buzz relay architecture is a modular, multi-tenant Nostr relay implementation that supports the NIP-29 protocol over WebSocket while exposing complementary HTTP APIs for media, Git, and webhook services.**

The Buzz relay serves as the central server powering the Buzz ecosystem, designed from the ground up to handle isolated community environments (tenants) within a single process. Unlike traditional monolithic relays, the block/buzz codebase separates concerns into distinct crates and modules, enabling independent testing and evolution of each subsystem. This architecture supports both real-time WebSocket messaging and synchronous HTTP operations, making it suitable for diverse client applications ranging from mobile apps to CI pipelines.

## Core Components and Module Structure

The relay implementation in `crates/buzz-relay` follows a layered architecture where each responsibility lives in a dedicated module. This separation ensures that WebSocket routing, state management, and protocol handlers remain isolated and testable.

### Entry Point and Runtime Lifecycle

The journey begins in [`buzz-relay/src/main.rs`](https://github.com/block/buzz/blob/main/buzz-relay/src/main.rs), which serves as the program entry-point. This file parses the TOML configuration, initializes the asynchronous Tokio runtime, and spawns both the HTTP server and WebSocket listener on port 3000. The main function coordinates the startup sequence, ensuring that database connection pools, Redis clients, and telemetry collectors are initialized before accepting traffic.

### WebSocket Routing and Authentication

Incoming WebSocket messages land in [`buzz-relay/src/router.rs`](https://github.com/block/buzz/blob/main/buzz-relay/src/router.rs), the nerve center of the relay. The router inspects each message's Nostr `kind` and dispatches it to the appropriate handler in `buzz-relay/src/handlers/`. Before dispatch, the router performs NIP-42 authentication validation via [`src/connection.rs`](https://github.com/block/buzz/blob/main/src/connection.rs) and resolves tenancy based on the `host` header or explicit `community` tags. This ensures that every request is associated with a specific `TenantId` before reaching business logic.

### Per-Tenant State Management

The [`buzz-relay/src/state.rs`](https://github.com/block/buzz/blob/main/buzz-relay/src/state.rs) module maintains runtime state for each active tenant. Rather than sharing global mutable state, Buzz instantiates isolated `State` structs containing in-memory caches, Postgres connection pools, and Redis pub/sub clients the first time a tenant receives a request. These state objects persist for the process lifetime, providing complete data isolation between communities while maximizing connection reuse.

### Protocol Handlers and HTTP API

The `buzz-relay/src/handlers/` directory contains specialized handlers for Nostr operations: [`event.rs`](https://github.com/block/buzz/blob/main/event.rs) handles ingestion, [`query.rs`](https://github.com/block/buzz/blob/main/query.rs) manages subscription filters, and [`media.rs`](https://github.com/block/buzz/blob/main/media.rs) processes media uploads. Each handler validates cryptographic signatures, interacts with the database layer (`buzz-db`), and publishes updates to connected clients.

Complementing the WebSocket interface, `buzz-relay/src/api/*` exposes equivalent HTTP endpoints. Files like [`buzz-relay/src/api/media.rs`](https://github.com/block/buzz/blob/main/buzz-relay/src/api/media.rs) wrap Nostr logic in RESTful interfaces, enabling desktop applications and CI pipelines to interact with the relay without maintaining persistent WebSocket connections.

### Mesh Networking and Audio Subsystems

For horizontal scalability, the optional mesh layer in `buzz-relay/src/mesh_*` allows multiple relay instances to form a cluster. The [`mesh_boot.rs`](https://github.com/block/buzz/blob/main/mesh_boot.rs) module handles node discovery and event replication, ensuring eventual consistency across distributed nodes.

The real-time voice chat functionality resides in [`buzz-relay/src/audio/room.rs`](https://github.com/block/buzz/blob/main/buzz-relay/src/audio/room.rs), implementing WebRTC-style rooms that leverage the relay's existing pub/sub infrastructure for signaling and session management.

### Telemetry and Observability

The [`buzz-relay/src/telemetry.rs`](https://github.com/block/buzz/blob/main/buzz-relay/src/telemetry.rs) module exposes Prometheus-compatible metrics for monitoring system health, request latency, and per-tenant throughput, enabling operators to track resource utilization across isolated communities.

## Multi-Tenant Design and Isolation

Buzz treats every community as a distinct **tenant**, with isolation enforced at multiple layers. Tenancy resolution occurs in [`buzz-relay/src/tenant.rs`](https://github.com/block/buzz/blob/main/buzz-relay/src/tenant.rs), where the `Tenant` struct encapsulates community-specific configuration.

Once identified, the `TenantId` flows through all downstream handlers, ensuring strict separation of:

- **Database schemas**: Postgres uses schema-per-tenant isolation, while Redis employs key namespacing
- **Media storage**: MinIO object storage prefixes segregate uploaded content by community
- **Event namespaces**: Nostr event kinds and ID ranges remain logically separated through filtering

This design allows a single relay process to host thousands of distinct communities without risk of data leakage or resource contention.

## Event Flow: From Client to Persistence

Understanding the Buzz relay architecture requires tracing the path of a Nostr event through the system. The implementation follows a four-stage pipeline that supports both WebSocket and HTTP ingress.

### 1. Connection and Authentication

A client initiates a WebSocket connection to `ws://<relay>:3000`. The connection handler in [`src/connection.rs`](https://github.com/block/buzz/blob/main/src/connection.rs) negotiates the WebSocket upgrade and immediately enforces NIP-42 authentication, validating the client's public key and cryptographic signature against the challenge.

### 2. Event Ingestion and Validation

Upon receiving an `EVENT` message, [`buzz-relay/src/handlers/event.rs`](https://github.com/block/buzz/blob/main/buzz-relay/src/handlers/event.rs) performs strict validation. The handler verifies the event signature, checks timestamp bounds, and ensures the publishing pubkey has authority within the resolved tenant context. Invalid events are rejected before reaching storage layers.

### 3. Persistence and Fan-Out

Validated events are written to Postgres via the `buzz-db` crate, ensuring durable storage. Simultaneously, the handler publishes the event to Redis pub/sub channels managed by `buzz-pubsub`. This dual-write strategy ensures that all connected WebSocket clients with matching filters receive real-time updates without polling the database.

### 4. Optional Mesh Replication

If the relay participates in a mesh cluster, [`buzz-relay/src/mesh_boot.rs`](https://github.com/block/buzz/blob/main/buzz-relay/src/mesh_boot.rs) asynchronously replicates the event to peer nodes. This gossip protocol guarantees eventual consistency across geographically distributed relay instances while maintaining the same tenant isolation boundaries.

## Extensibility and Protocol Evolution

The Buzz relay architecture prioritizes forward compatibility through its modular handler system. New Nostr event kinds are defined in [`buzz-core/src/kind.rs`](https://github.com/block/buzz/blob/main/buzz-core/src/kind.rs), with corresponding implementations added to `buzz-relay/src/handlers/`.

Because [`buzz-relay/src/router.rs`](https://github.com/block/buzz/blob/main/buzz-relay/src/router.rs) dispatches purely on the `kind` field, adding features requires no changes to the WebSocket protocol or HTTP routing tables. Developers simply implement a new handler module and register it in the router's dispatch map. This design enables rapid iteration on protocol extensions while maintaining backward compatibility with existing NIP-29 clients.

## Practical Deployment Examples

Starting a local relay instance requires minimal configuration:

```bash
just relay

```

This command launches the relay on `ws://localhost:3000`, ready to accept WebSocket connections and HTTP requests.

Connecting via WebSocket using Node.js:

```javascript
import WebSocket from 'ws';
const ws = new WebSocket('ws://localhost:3000');

ws.onopen = () => {
  // NIP-42 authentication required
  ws.send(JSON.stringify(['AUTH', '<pubkey>', '<challenge>', '<sig>']));
};

ws.onmessage = (msg) => console.log('Relay →', msg.data);

```

Publishing events via HTTP for non-WebSocket clients:

```bash
curl -X POST http://localhost:3000/events \
  -H 'Content-Type: application/json' \
  -d '{
        "pubkey":"<your_pubkey>",
        "kind":40001,
        "content":"Hello Buzz!",
        "created_at":1700000000,
        "tags":[],
        "sig":"<signature>"
      }'

```

Querying events with filters:

```bash
curl -X POST http://localhost:3000/query \
  -H 'Content-Type: application/json' \
  -d '{"kinds":[40001],"limit":10}'

```

## Summary

The Buzz relay architecture delivers a production-ready, multi-tenant Nostr relay with distinct separation of concerns:

- **Modular crate structure** isolates WebSocket routing, state management, and protocol handlers into testable units
- **Multi-tenancy** ensures complete data isolation between communities through the `Tenant` struct and `TenantId` propagation
- **Dual-protocol support** serves both persistent WebSocket clients and stateless HTTP consumers through shared handler logic
- **Horizontal scalability** via optional mesh networking allows clusters to synchronize events while maintaining tenant boundaries
- **Extensible design** enables new Nostr kinds through pure handler additions in `buzz-relay/src/handlers/` without protocol changes

## Frequently Asked Questions

### How does Buzz handle authentication for WebSocket connections?

Buzz implements NIP-42 authentication in [`buzz-relay/src/connection.rs`](https://github.com/block/buzz/blob/main/buzz-relay/src/connection.rs), requiring clients to provide a valid public key and cryptographic signature within the initial handshake. The router validates these credentials before dispatching messages to handlers, ensuring that all subsequent operations execute within the authenticated identity's tenant context.

### What database systems does the Buzz relay use?

The architecture employs **Postgres** for durable event storage and **Redis** for pub/sub fan-out and caching. The [`buzz-relay/src/state.rs`](https://github.com/block/buzz/blob/main/buzz-relay/src/state.rs) module maintains connection pools for both systems on a per-tenant basis, ensuring that database queries and cache operations remain isolated between communities through schema separation and key namespacing.

### Can multiple Buzz relay instances form a cluster?

Yes, the optional mesh networking layer in `buzz-relay/src/mesh_*` and [`src/mesh_boot.rs`](https://github.com/block/buzz/blob/main/src/mesh_boot.rs) enables multiple relay instances to discover peers and replicate events across nodes. This implementation provides eventual consistency for distributed deployments while preserving the multi-tenant isolation guarantees of the single-node architecture.

### How do I add support for a new Nostr event kind to the relay?

Extend the relay by defining the new kind constant in [`buzz-core/src/kind.rs`](https://github.com/block/buzz/blob/main/buzz-core/src/kind.rs) and implementing the handler logic in `buzz-relay/src/handlers/`. The WebSocket router in [`src/router.rs`](https://github.com/block/buzz/blob/main/src/router.rs) automatically dispatches messages based on the `kind` field, so no HTTP endpoint or routing table modifications are required to support new protocol features.