Chapter 6

Kinds & NIPs

A periodic table of event kinds and the specs that define them.

Same envelope, different stamp! Let's sort the mail by kind.

One envelope, many stamps

So far every event has looked the same: an id, a pubkey, a timestamp, some tags, some content and a signature. A tweet-style note, your profile, a “like”, a blog post and a Lightning receipt all travel in the exact same envelope.

So how does an app know which is which? One tiny field: the kind. It’s just an integer, like a stamp on the envelope. 1 means “short text note”, 0 means “my profile”, 7 means “reaction”, 30023 means “long-form article”. That’s it. No new message types, no new endpoints: Nostr grows by inventing new numbers.

Think of the kind as the section of a library. The books (events) are all bound the same way, but the sticker on the spine tells the librarian (the relay) which shelf to put it on, and tells readers (clients) how to display it.

The periodic table of kinds

Chemists sort elements by their properties. We can do the same with kinds: the color of a tile is its storage category, which is decided purely by the number’s range. Click around: every tile opens a real example event. Try to visit all four colors.

The periodic table of kinds

Every tile is an event kind. Filter by storage category or search, then pick a tile to see a real example event.

Show categories

60 kinds shown

Explored 1 of 4 categories

Regular Relays keep every one.

Replaceable Relays keep only the latest per author.

Ephemeral Relays forward but never store them.

Addressable Relays keep the latest per author and d tag.

Short text note

Kind 1

Regular

A plain-text post, like a tweet.

What relays do
Relays keep every one. Range: 1–2, 4–44, 1000–9999
Example event

A real signed event from our fixture set.

  { "id": "ea2e3eb8fe5e6cfbc202da21df546f68c6673e9a00c0aed61cffbac7aed9faf7" ,"pubkey": "a73883912a48c3551c1548fd454876d577126a61c76b5486c807bfec5869e183" ,"created_at": 1735686600 ,"kind": 1 , "tags": [  ] ,"content": "testing testing is this thing on" ,"sig": "82bc74fdbd5b113f257f4c8b2a6db64410ae897362bd42839fe9a34737d5ecb518a99f8517058ef8c2beadc222142e4d68f034e829edc9dd1b6bd13d2a139a7d"  } 
Ask a relay for this kind
["REQ","kinds-demo",{"kinds":[1],"limit":10}]

Under the hood: where kinds are registered Show details

There is no central registry server: the list of known kinds lives in the README of the nostr-protocol/nips repository, next to the NIP that defines each one. Examples in the table above are either real fixture events (verified signatures) or templates signed in your browser with a public demo key using a fixed auxRand, so the bytes are identical on every visit.

import { kinds } from "nostr-tools";

kinds.ShortTextNote;            // 1
kinds.LongFormArticle;          // 30023
kinds.classifyKind(30023);      // "parameterized" (nostr-tools' older name for addressable)
kinds.isReplaceableKind(10002); // true

Four ways to be stored

The number tells a relay what to keep. NIP-01 splits the number line into four neighborhoods:

  • Regular (1, 2, 4–44, 1000–9999): a diary. Every page is kept. Notes, reactions, reposts and zap receipts pile up forever (or until the relay decides otherwise).
  • Replaceable (0, 3, 10000–19999): a whiteboard. Each person gets one per kind; writing a new one wipes the old. Your profile (kind 0), your follow list (kind 3) and your relay list (kind 10002) work this way.
  • Ephemeral (20000–29999): a phone call. Relays pass it to whoever is listening right now and then forget it. Perfect for login challenges and signer chatter.
  • Addressable (30000–39999): a set of labeled whiteboards. One per person, per kind, per d tag. That’s how you can edit several long-form articles independently.

Play with it. Publish a few versions, switch categories, and then try re-sending an older copy:

Relay storage simulator

Publish several versions of an event and watch what the relay keeps on its shelf.

Category to simulate

Relay shelf 0 events stored

The shelf is empty.

Live subscribers

Nobody has received anything yet.

Who wins a tie?

For replaceable and addressable events the newest created_at wins. If two versions share the exact same second, relays keep the one with the lowest id (first in alphabetical order), so every relay ends up agreeing on the same winner no matter which copy arrived first.

Under the hood: NIP-01 storage rules Show details

The exact rules from NIP-01:

Category Range Relay keeps
regular 1000 <= n < 10000 || 4 <= n < 45 || n == 1 || n == 2 every event
replaceable 10000 <= n < 20000 || n == 0 || n == 3 latest per (pubkey, kind)
ephemeral 20000 <= n < 30000 nothing (forward only)
addressable 30000 <= n < 40000 latest per (pubkey, kind, d)

Kinds 45–999 and 40000–65535 fall outside every range: NIP-01 says nothing about storing them, and most relays treat them as regular. An addressable event is pointed at with its address kind:pubkey:d, either in an a tag or encoded as an naddr:

["a", "30023:e550c6e92808f358382b7b8c14345344f5ef9a299529834d1c26d57b6ace44cc:relays-explained", "wss://relay.alpha.example"]

Asking for “the current version” is a normal filter, because the relay only stores one:

["REQ", "article", { "kinds": [30023], "authors": ["e550c6…"], "#d": ["relays-explained"] }]

Want to test your intuition? Type any number and see which neighborhood it lives in:

Kind number classifier

Kind 30023 is Addressable.

Relays keep the latest per author and d tag.

We know this one: Long-form article (NIP-23).

NIPs: how Nostr grows without a boss

Who decides that 7 means “reaction”? Nobody, and everybody. A NIP (Nostr Implementation Possibility) is a short, public document describing a convention: which kind to use, which tags, what the content means. They live in one GitHub repository, but they work more like recipes shared at a potluck than laws:

  1. Someone has an idea. A developer wants polls, or calendars, or marketplaces.
  2. They build it first. Ideally in a real client and relay, picking a kind number nobody else uses.
  3. They open a pull request. People argue, simplify, and poke holes in it in public.
  4. It gets merged when it’s real. The README asks that a NIP be implemented in at least two clients and one relay (where applicable), make sense, be optional and backwards-compatible, and not add a second way to do the same thing.

The key trick is the word optional. A client that doesn’t understand kind 31922 (a calendar event) simply ignores it. Nothing breaks. That’s why Nostr can grow sideways: microblogging, long-form, livestreams, code collaboration and wallets all share the same relays and the same keys.

NIP names are not always numbers

Most NIPs have two-digit decimal names (01, 57), but newer ones may use hex-looking names such as 7D (threads) or C7 (chats). The kind number and the NIP number are unrelated: kind 7 is defined in NIP-25, not NIP-07.

Under the hood: NIPs worth reading Show details

Useful starting points in the NIPs repository:

  • NIP-01: the event format, kind 0 and the four storage categories (kind 1 is specified in NIP-10)
  • NIP-02: follow list (kind 3)
  • NIP-23 (spec): long-form content (kind 30023, drafts 30024)
  • NIP-51: lists, standard (10000+) and sets (30000+)
  • NIP-65: relay list metadata (kind 10002)
  • NIP-31: put a human-readable alt tag on custom kinds, so clients that don’t understand them can still show something. The NIPs README now marks NIP-31 as unrecommended, but an alt tag on a custom kind is still a harmless courtesy
  • NIP-89: apps announce which kinds they handle (31990), users recommend apps (31989)

Inventing a private kind for your app? Pick an unused number in the right range for the storage behavior you want, add an alt tag, and document it.

Quick check

You update your profile picture three times. How many kind 0 events does a well-behaved relay keep for you?

Choose one answer

Which kind lets you keep several independently editable blog posts?

Choose one answer

A client receives an event with a kind it has never heard of. What should it do?

Choose one answer

Takeaways

  • Every event has a kind: a number that says what it is (a note, a profile, a reaction…).
  • The number's range tells relays how to store it: regular (keep all), replaceable (keep latest), ephemeral (keep none), addressable (keep latest per d tag).
  • For replaceable and addressable events, the newest created_at wins; ties go to the lowest id.
  • NIPs are the community's open specs. A new kind is just a number plus a NIP that explains it.
  • Clients ignore kinds they don't understand, so new features never break old apps.