Nostrfi
/Docs
Browse documentation
Owner: NostrfiLast reviewed: 2026-07-23

Relay role and architecture

What a relay does

A Nostr relay is a server that stores signed events and serves them to clients over WebSocket connections. Clients publish events to relays and subscribe to event feeds from relays. Each client chooses which relays to connect to and can connect to multiple relays simultaneously.

The relay does not hold users' private keys. Clients sign events locally and send the signed event to the relay. The relay verifies the signature before storing or serving the event.

System architecture

Nostrfi Relay is a single-process Go application. One HTTP server exposes both the NIP-11 information document and a WebSocket endpoint.

Nostr client
    | HTTP GET with Accept: application/nostr+json
    | WebSocket: EVENT, REQ, CLOSE, AUTH, NEG-*
    v
RelayHandler
    |-- connection authentication and subscriptions (in memory)
    |-- live event fan-out (in process)
    |-- NIP-11 response
    +-- Negentropy sessions (in memory)
             |
             v
       RelayService
             |
             v
      DuckDBRepository
        db/relay.db

Components

Entry point

cmd/relay/main.go loads configuration, opens the DuckDB database, wires the repository, service, and handler, and listens on port 8080. SIGINT or SIGTERM starts a five-second graceful HTTP shutdown before the database is closed.

Handler

The handler owns WebSocket upgrades, connected-client tracking, per-connection subscriptions, authentication identity, Negentropy sessions, Nostr message parsing, signature verification, and synchronous live fan-out to matching subscriptions.

Service

The service layer defines the boundary between transport logic and storage.

Persistence

A DuckDB repository stores events in two tables: events (identity, author, timestamp, kind, content, signature, d tag, expiration) and tags (indexed tag name and first value keyed by event ID).

Scaling

The design is single-instance. Connected clients, subscriptions, authentication, live broadcasts, and Negentropy sessions are local to one process. Horizontal scaling requires architectural work.