Relay Communication
What You'll Learn
In this tutorial, you'll master:
- How Nostr relays work and their role in the network
- WebSocket communication patterns
- Subscription filters and real-time updates
- Publishing events to multiple relays
- Handling connection failures and retries
- Relay selection strategies
Prerequisites
- Understanding of Nostr events
- Basic WebSocket knowledge
- JavaScript async/await patterns
Understanding Relays
Relays are the backbone of the Nostr network. They're simple servers that:
- Store events submitted by clients
- Serve events to clients based on filters
- Relay events between clients in real-time
- Maintain no user accounts - just events
Think of relays as smart databases that speak a common protocol.
The Relay Protocol
Nostr uses WebSockets for real-time communication between clients and relays. All messages are JSON arrays with specific formats:
Client to Relay Messages
Message Type | Format | Purpose |
---|---|---|
EVENT |
["EVENT", <event>] |
Publish an event |
REQ |
["REQ", <sub_id>, <filters>...] |
Subscribe to events |
CLOSE |
["CLOSE", <sub_id>] |
Close a subscription |
AUTH |
["AUTH", <event>] |
Authenticate with relay |
COUNT |
["COUNT", <sub_id>, <filters>...] |
Count matching events |
Relay to Client Messages
Message Type | Format | Purpose |
---|---|---|
EVENT |
["EVENT", <sub_id>, <event>] |
Send event to client |
EOSE |
["EOSE", <sub_id>] |
End of stored events |
OK |
["OK", <event_id>, <true\|false>, <message>] |
Event publish result |
NOTICE |
["NOTICE", <message>] |
Human-readable message |
CLOSED |
["CLOSED", <sub_id>, <message>] |
Subscription closed |
AUTH |
["AUTH", <challenge>] |
Authentication challenge |
COUNT |
["COUNT", <sub_id>, <count>] |
Event count response |
Connecting to Relays
Let's start with a basic relay connection:
import { relayInit } from 'nostr-tools'
async function connectToRelay(url) {
const relay = relayInit(url)
relay.on('connect', () => {
console.log(`Connected to ${url}`)
})
relay.on('error', () => {
console.error(`Failed to connect to ${url}`)
})
relay.on('disconnect', () => {
console.log(`Disconnected from ${url}`)
})
try {
await relay.connect()
return relay
} catch (error) {
console.error('Connection failed:', error)
throw error
}
}
// Usage
const relay = await connectToRelay('wss://relay.damus.io')
Best Practices
Relay Communication Best Practices
- Use Multiple Relays: Never rely on a single relay
- Handle Failures Gracefully: Always have fallback mechanisms
- Monitor Health: Track relay performance and switch when needed
- Deduplicate Events: Handle the same event from multiple relays
- Limit Subscriptions: Don't overload relays with too many filters
- Close Unused Subscriptions: Clean up when done
- Respect Rate Limits: Check relay info for limitations
Common Pitfalls
- Not handling disconnections: Relays can go offline
- Forgetting to unsubscribe: Can lead to memory leaks
- Too many concurrent subscriptions: Can overwhelm clients
- Ignoring relay limitations: Check max_subscriptions and other limits
- Not validating events: Always verify signatures and format
Next Steps
Now you can explore: