Chapter 02 - Social
02
Nostr Implementation Possibility - Hex № 02

Follow List

One event that lists every profile a user follows. A new list replaces the old one, so the relay always holds the latest social graph.

1 Overview

A client needs a way to know who a user follows. NIP-02 defines one kind 3 event for this job: the follow list.

The follow list holds one p tag for each followed profile. A user publishes a new follow list every time their follows change. The newest kind-3 event replaces every older one from the same pubkey, because kind 3 is a replaceable kind under NIP-01.

Clients use the follow list to build a feed, back up a social graph, suggest new profiles to follow, share known relays, and build local "petname" tables. This NIP is marked final and optional: its wire format will not change, but a client does not have to implement it.

Hint!

NIP-02 was formerly named "Contact List and Petnames" and its kind-3 event was called a "contact list". Both names now mean the same event. See §6 History.

2 The Follow List Event

A follow list is an event with "kind": 3. It contains one p tag for every followed or known profile. The content field is not used; by convention, clients set it to an empty string.

p tag - full form
["p", <32-byte hex pubkey>, <main relay URL, or "" >, <petname, or "" >]
p tag fields
PositionFieldRule
0tag nameAlways the literal string "p".
1pubkeyThe 32-byte hex public key of the followed profile. Required.
2relay URLA relay where events from that key can be found. Set to an empty string if not needed.
3petnameA local nickname for that profile. Set to an empty string, or leave it out, if not needed.
p tag name pubkey 64-char hex, required relay URL optional, "" allowed petname optional
Fig. 2-1 — p tag anatomy. Only the tag name and the pubkey are required. The relay URL and petname may be empty strings.
Example - kind 3 follow list
{
  "kind": 3,
  "tags": [
    ["p", "91cf9..4e5ca", "wss://alicerelay.com/", "alice"],
    ["p", "14aeb..8dad4", "wss://bobrelay.com/nostr", "bob"],
    ["p", "612ae..e610f", "ws://carolrelay.com/ws", "carol"]
  ],
  "content": "",
  // id, pubkey, created_at, sig — see NIP-01
}

3 Replacing and Updating a Follow List

Every new follow list overwrites the past ones. A published follow list must contain the full set of follows, not just the change. Relays and clients should delete past follow lists as soon as they receive a new one, because kind 3 is a replaceable kind: a relay keeps only the latest event for each pubkey + kind pair.

When a user adds new follows to an existing list, clients should append the new p tags to the end of the list. This keeps the list in chronological order, oldest follow first.

kind:3 event created_at 1000 (v1) kind:3 event created_at 2000 (v2) Relay Stored only v2 kept v1 (older) v2 (newer)
Fig. 2-2 — Replace-on-publish. The relay keeps only the newest kind-3 event per pubkey. Older follow lists are discarded.

4 Uses

Follow list backup

A relay may store events for a long time. A user can rely on their kind-3 event to back up their follow list. They can recover the list on a new device by fetching it from any relay that has it.

Profile discovery and context augmentation

A client may read a kind-3 event to show which profiles a user follows. A client may also compare follow lists between users, and suggest new profiles to follow based on shared follows. A client may show this data in other contexts too.

Relay sharing

A client may publish a follow list where each p tag names a good relay for that followed profile. Other clients can read these relay URLs and update their own relay lists. This spreads relay knowledge between clients and increases censorship resistance.

Petname scheme

A client can use follow lists from other users to build a local petname table. A petname is a local nickname a user picks for a pubkey. This removes the need for a single global human-readable name.

Petnames chain together. If your follow list names a pubkey "erin", and erin's own follow list names another pubkey "david", a client may show that second pubkey as "david.erin" to you. One more hop gives "frank.david.erin".

Example - petname chain
-- your follow list --
["p", "21df6d143fb96c2ec9d63726bf9edc71", "", "erin"]

-- erin's follow list --
["p", "a8bb3d884d5d90b413d9891fe4c4e46d", "", "david"]

-- david's follow list --
["p", "f57f54057d2a7af0efecc8b0b66f5708", "", "frank"]

-- your client shows --
21df6d14…  → "erin"
a8bb3d88…  → "david.erin"
f57f5405…  → "frank.david.erin"
You erin 21df6d1… david.erin a8bb3d8… frank.david.erin f57f540… follows follows follows
Fig. 2-3 — Petname chain. Each hop away from you adds one more name segment, built from follow lists your client already has.
Tech Note

The source spec defines a pubkey as a "32-byte hex key" (64 hex characters). The petname-scheme example pubkeys, such as 21df6d143fb96c2ec9d63726bf9edc71, are only 32 hex characters (16 bytes) and are not truncated with an ellipsis like the earlier example keys. They cannot be real pubkeys as written. Treat them as illustrative placeholders only, not as a literal wire example.

5 Worked Example

The session below shows Bob publishing a follow list, then Alice fetching it. Orange lines go to the relay. Blue lines come from the relay.

Session transcript - wss://relay.example.com
-- Bob publishes his follow list --
→ ["EVENT", {"id":"7c2f19ab…","pubkey":"14aeb..8dad4","created_at":1749762600,
     "kind":3,
     "tags":[
       ["p","91cf9..4e5ca","wss://alicerelay.com/","alice"],
       ["p","612ae..e610f","ws://carolrelay.com/ws","carol"]
     ],
     "content":"","sig":"9a31dd42…"}]
← ["OK", "7c2f19ab…", true, ""]

-- Alice requests Bob's follow list --
→ ["REQ", "bob-follows", {"kinds":[3], "authors":["14aeb..8dad4"]}]
← ["EVENT", "bob-follows", {"id":"7c2f19ab…", "kind":3, "tags":[…], "content":"", …}]
← ["EOSE", "bob-follows"]
→ ["CLOSE", "bob-follows"]

-- later, Bob adds one more follow and republishes --
→ ["EVENT", {"id":"c04e88de…","pubkey":"14aeb..8dad4","created_at":1749849000,
     "kind":3,
     "tags":[
       ["p","91cf9..4e5ca","wss://alicerelay.com/","alice"],
       ["p","612ae..e610f","ws://carolrelay.com/ws","carol"],
       ["p","f57f540..5708","","frank"]
     ],
     "content":"","sig":"2be671fa…"}]
← ["OK", "c04e88de…", true, ""]
-- the relay now discards the 7c2f19ab… event; c04e88de… is Bob's only follow list --

6 Version History

NIP-02 has kept the same kind-3 wire format since 2022. Changes have been renames and clarifications. Notable changes, newest first:

  • 20262026-06Cosmetic: the example code fence label changed from jsonc to yaml; no wire-format change.
  • 20242024-01Clarified that clients should append new follows to the end of the list, keeping chronological order.
  • 20242024-02 - 2024-09Reworded the content rule to "not used" (from "can be anything, ignored"); minor JSON-comment formatting.
  • 20232023-12Renamed the NIP from "Contact List and Petnames" to "Follow List"; the kind-3 event is now called a follow list, not a contact list.
  • 20232023-11Removed all per-NIP author bylines repository-wide, including author:fiatjaf and author:arcbtc on this page.
  • 20232023-01 - 2023-03Typo fixes: spelling of "censorship-resistance" and a missing closing brace in the example event.
  • 20222022-11Status changed from draft to final: the wire format was declared stable.
  • 20222022-06Disallowed null placeholders in tag entries. Relay URL and petname must be an empty string, not null, when absent.
  • Origin2022-05-01fiatjaf published the spec as "Contact List and Petnames", co-credited with arcbtc, in the migration to the nostr-protocol/nips repository.

Original Proposal - Credits

Authorfiatjaf (co-credited with arcbtc in the original byline)
First commit2022-05-01 — "migrate nips from main nostr repo."
Statusfinal - optional — stable wire format, implementation not required
Source02.md on GitHub - full change history

7 See Also

  • NIP-01 — defines the event object, the p tag's basic form, and the replaceable-kind rule that this NIP depends on.
  • NIP-51 — generic lists. Follow lists are a fixed, single-purpose case of the more general list format.
  • NIP-65 — a dedicated relay list event, a more structured alternative to the relay-sharing use of the p tag here.
  • NIP-19 — bech32 npub encoding for the raw hex pubkeys stored in p tags.
  • NIP-24 — extra profile metadata a client can show alongside a followed pubkey.