Follow an event

Select an action. The route shows where copies normally go under the outbox model.

Your write relays are your outbox

Clients fetch events authored by you from the relays marked write in your kind 10002 list.

Your read relays are your inbox

Other clients send events that tag you to relays marked read in your kind 10002 list.

Two to four is the design target

NIP-65 recommends a small list. A few distinct operators give useful redundancy without excessive connections.

Why the outbox model exists

Without relay discovery, two correct clients can use the same network and never meet.

The fixed-relay failure

Alice publishes successfully. A client queries its own default relays. The relay sets do not overlap, so Alice appears empty.

Alice Signs an article
Alice's relays nostr.wine, relay.damus.io
×
Client defaults Two unrelated relays
Reader's client Finds no Alice events

The relay list is an event

Kind 10002 gives each public key a small, replaceable relay map.

{
  "kind": 10002,
  "pubkey": "<alice>",
  "tags": [
    ["r", "wss://nostr.wine", "write"],
    ["r", "wss://relay.damus.io"],
    ["r", "wss://inbox.alice.net", "read"]
  ],
  "content": ""
}
writeAlice publishes there. Fetch Alice's events there.
readAlice checks there for events that tag her.
noneThe relay performs both roles.

The two routing rules

The email terms describe direction. They do not make relay data private.

Read Alice
Bob's clientRequests Alice's pubkey
Alice's write relaysHer outbox
Reach Alice
Bob's replyTags Alice
Alice's read relaysHer inbox
Keep Bob visible
The same replyAuthored by Bob
Bob's write relaysHis followers read it here

The bootstrap sequence

The relay list has to be found before it can direct the query. Public indexers break that loop.

  1. Ask an indexerREQ kinds:[10002], authors:[alice]
  2. Receive Alice's mapThe indexer returns Alice's newest accepted relay-list event.
  3. Cache by public keyThe client keeps the resolved write and read relays for this session.
  4. Query Alice's outboxThe client requests kind 30023 or other authored events from Alice's write relays.
  5. Use relay hints toonprofile, nevent, p, e, and a hints can add direct routes.
An indexer is a bootstrap directory, not a complete account database.

NIP-65 defines no special indexer protocol. Each indexer decides which identity kinds it accepts, how long it keeps them, and whether it offers search or general relay service.

Relay roles are policies

A relay can perform several roles. Nostr does not assign one fixed class to each server.

Write relay

outbox

Stores events authored by its users. Other clients visit it when they want that author's posts, articles, or profile.

Named by kind 10002 with write, or with no marker.

Read relay

inbox

Receives events addressed to a user, such as mentions, comments, and highlights that tag the user.

Named by kind 10002 with read, or with no marker.

Indexer

directory

Helps clients find identity records and relay lists. Common indexers keep kinds 0, 3, and 10002, but each indexer sets its own policy.

An indexer is not the account server or the only authoritative copy.

Search relay

NIP-50

Builds a text index and answers search filters. It may ingest public events from elsewhere and rank results in its own way.

Kind 10007 can advertise a user's preferred search relays.

App relay

application data

Stores events for one app or community. It can require payment, membership, authentication, or selected kinds.

App data does not need to use the same relays as public social data.

DM relay

NIP-17

Stores gift-wrapped messages for a recipient. Kind 10050 lists these relays separately from the general NIP-65 inbox.

Good DM relays use NIP-42 authentication before returning kind 1059.

Your secret key is not relay data

An nsec lives in a signer, local key store, or backup. A legitimate client never publishes it.

Local state stays local until a client publishes it

Drafts, caches, reading position, and app settings can remain in a device database. Nostr does not sync them by default.

Profiles can point outside Nostr

Kind 0 can point to an image, NIP-05 name, or payment endpoint. Those files and services live on web servers.

“The indexer has my profile” is incomplete.

It has one accepted copy. Your write relays can hold other copies. Caches, search relays, archives, and other users can also retain snapshots.

PlebChat uses two relay roads

The event kind selects a policy road before the event is signed. The two relay pools never mix.

Application roadWhere PlebChat works
Configured app relays
Encrypted sync, books, saved articles, private annotations, settings, skills, prompts, debates, favorites, and other PlebChat records.
Operation Relays used Reason
Resolve a public key Fixed indexers Fetch kind 10002 before deciding where that person's events live.
Read own identity Indexers + own write relays Compare accepted copies of kinds 0, 3, 10000, 10002, and 10063. Newest valid event wins.
Publish identity Own write relays + indexers Keep the current record in the outbox and make its routing data discoverable.
Read another author Their write relays + relay hints The author's kind 10002 tells clients where authored events should be available.
Publish a comment or highlight Own write relays + each tagged person's read relays Your followers need your copy. Tagged people need delivery to their inbox relays.
Discover articles Curated feed relays and search relays Discovery asks “what is interesting?” Outbox routing asks “where does this author publish?”
Sync PlebChat data Configured app relays only Private application records must not leak into the public social pool.

Why a missing identity read can destroy data

Kind 3 is the whole follow list. It is not an “add one follow” event.

Real list400 follows on the user's write relays
Wrong queryClient asks unrelated default relays
False empty stateNo event is mistaken for “follows nobody”
Unsafe writeClient publishes one p tag for the new follow
ReplacementShared relays keep one follow instead of 400

“Unreachable” is not “missing”

If no indexer answers, the client does not know whether a relay list or contact list exists. It must not construct a replacement from an empty result.

timeoutUnknown state. Refuse the identity write.
EOSEThat relay completed the query without a matching event.
eventCarry the current content and unrelated tags into the edit.

One policy boundary prevents two bug classes

A social event sent only to an app relay becomes invisible to the wider network. An encrypted app event sent to the social pool spreads private ciphertext and metadata.

socialResolve authors and recipients through NIP-65.
appUse only the configured application relay set.
guardReject a kind placed on the wrong road before signing.

The client resolves outboxes itself

PlebChat uses a bounded, explicit resolver instead of NDK's automatic outbox routing.

Discover remains curated

Feed relays find broad long-form content. A specific author's view adds that author's write relays.

The public relay is still pending

The pre-release app relay remains restricted. The planned public relay is separate from the paygate and has its own abuse controls.

Kind ranges control lifetime

These rules tell a relay which versions it should keep. Relay implementations can still differ.

1, 2, 4–44, 1000–9999 Regular events

Each event ID is its own record. Notes, reactions, comments, highlights, gift wraps, and file metadata usually remain as separate events.

0, 3, 10000–19999 Replaceable events

One current event exists for each author and kind. A profile, follow list, or relay list update replaces the older version.

20000–29999 Ephemeral events

Relays forward them to current subscribers but should not store them. Kind 21059 is an ephemeral gift wrap.

30000–39999 Addressable events

The current record is selected by kind, author, and d tag. One author can have many articles or named lists.

Replaceable means “newest visible version,” not “old versions never existed.”

A relay may discard an old version. Another relay, cache, or archive may still keep it.

Articles, comments, and highlights do not share one home

The links are in tags. The copies can sit on different relay sets.

Article · kind 30023

Addressable Markdown. Fetch it from the article author's write relays, relay hints, or a discovery relay.

Comment · kind 1111

A regular plaintext event. Uppercase tags identify the root. Lowercase tags identify the parent.

Highlight · kind 9802

A regular public quote. An a or e tag points to Nostr content. An r tag points to a URL.

Where comments reside

The commenter's write relays and the read relays of each tagged author, if the publishing client follows NIP-65.

Where highlights reside

The highlighter's write relays and the source author's read relays when the event tags that author.

Why a client can miss them

A client that checks only the article relay can miss replies delivered to the author's inbox relays.

Common kind atlas

Search by number, name, storage rule, or purpose. “App-specific” means another client may not understand the schema.

Standard kind does not always mean interoperable content

NIP-78 defines kind 30078 as a standard container for arbitrary app data. The d tag should identify the app and record. Only that app may understand the content. Custom kinds work in a similar way, but their number and schema come from the app.

  • Check the current kind registry before assigning a custom number.
  • Use a stable d tag for addressable records.
  • Encryption hides content, not the event kind, author, time, size, or public tags.