n0str (pronounced /ˈnoʊ.stər/) is a modern Nostr relay designed for maximum simplicity without sacrificing power. It's a single-binary, zero-dependency solution that brings professional-grade relay features to anyone, anywhere. You can try it out at wss://n0str.tani.cc.
Forget about complex Docker setups or external database migrations. n0str is a self-contained power tool. Download the binary, run it, and you're live. It embeds its own database (SQLite), making it the ultimate "drop-in" relay.
Most relays struggle with CJK (Chinese, Japanese, Korean) or complex scripts because they rely on simple whitespace tokenization. n0str is different. We leverage the standard Intl.Segmenter API to provide true language-aware indexing. Whether you're posting in English, Japanese, or Arabic, search just works.
Download the latest pre-compiled binary for your system from the Releases page.
# macOS/Linux
chmod +x n0str-linux-x64
./n0str-linux-x64-
Clone & Install:
git clone https://github.com/tani/n0str.git && cd n0str bun install
-
Start:
bun start
n0str is built to be a standard-compliant, feature-rich relay core.
- Embedded High-Performance DB: Native support for SQLite.
- Advanced Query Support: Complex tag filtering and counting (NIP-45).
- Negentropy Syncing: Lightning-fast state reconciliation (NIP-77).
- Security First: Native support for PoW (NIP-13) and Auth (NIP-42).
| NIP | Feature | Status |
|---|---|---|
| 01 | Basic Protocol Flow (EVENT, REQ, CLOSE) | ✅ |
| 13 | Proof of Work | ✅ |
| 42 | Client Authentication (AUTH) | ✅ |
| 50 | Human-Language Search (CJK Support) | 💎 |
| 77 | Negentropy Syncing | ✅ |
| ... | And 25+ more (see below for full list) | ✅ |
View All 30+ Supported NIPS
| NIP | Description |
|---|---|
| 02 | Contact List |
| 03 | OpenTimestamps |
| 05 | DNS-based Identifiers |
| 09 | Deletions |
| 11 | Relay Information |
| 12 | Generic Tag Queries |
| 15 | Nostr Marketplace |
| 16 | Event Treatment |
| 17 | Private DMs |
| 20 | Command Results |
| 22 | Timestamp Limits |
| 23 | Long-form Content |
| 25 | Reactions |
| 28 | Public Chat |
| 33 | Parameterized Replaceable Events |
| 40 | Expiration |
| 44 | Encrypted Payloads |
| 51 | Lists |
| 57 | Lightning Zaps |
| 65 | Relay List Metadata |
| 70 | Protected Events |
| 78 | App-specific Data |
n0str works out of the box with defaults, but can be fully customized via n0str.json or command-line arguments.
Create an n0str.json in the root directory:
{
"name": "My n0str Relay",
"description": "Fast and multi-lingual",
"pubkey": "[Your hex pubkey]",
"limitation": {
"max_message_length": 65536,
"max_subscriptions": 20
}
}Command-line arguments take precedence over the JSON config.
# Example: Run on port 8080 with a specific database and config file
./n0str --port 8080 --database ./relay.db --config ./custom-config.json --loglevel debug-p, --port <number>: Listen port (default:3000)-d, --database <path>: Database path or:memory:(default::memory:)-l, --loglevel <level>: Logging level (tracetoerror, default:info)-c, --config <path>: Configuration file path (default:n0str.json)-h, --help: Show help message-v, --version: Show version information
n0str's architecture is built on a clean, message-driven flow designed for auditability and extension.
sequenceDiagram
autonumber
participant C as Client
participant R as NostrRelay (Bun)
participant H as NostrMessageHandler
participant V as Validation (nostr.ts)
participant DB as EventRepository
participant W as WebSocketManager
rect rgb(240, 240, 240)
Note over C,V: Event Publishing (EVENT)
C->>R: ["EVENT", {event}]
R->>H: handleMessage(ws, msg)
H->>V: ClientMessageSchema (ArkType)
H->>V: validateEvent (Schema, NIP-13 PoW, Sig)
H->>V: validateCreatedAt (NIP-22)
H->>H: Check Expiration (NIP-40)
H->>H: Check Protected Event (NIP-70)
break Validation Failed
H->>C: ["OK", id, false, "error: ..."]
end
alt is regular event
H->>DB: saveEvent(event)
Note right of DB: Handles NIP-01/33 Replaceable Logic
end
H->>C: ["OK", id, true, ""]
H->>W: broadcast(event)
W->>W: matchFilters(ws.subscriptions, event)
W->>C: ["EVENT", subId, event]
end
rect rgb(245, 245, 245)
Note over C,DB: Subscription Flow (REQ)
C->>R: ["REQ", subId, filters...]
R->>H: handleReq(ws, payload)
H->>H: Store subscription in client data
loop for each filter
H->>DB: queryEvents(filter)
Note right of DB: FTS (NIP-50) with Intl.Segmenter
DB-->>H: events[]
loop for each unique event
H->>C: ["EVENT", subId, event]
end
end
H->>C: ["EOSE", subId]
end
- Zero Bloat: No massive dependency trees. Keep it lean, mean, and fast.
- Global First: Nostr is for the world. If it doesn't work in Japanese or Arabic, it doesn't work.
- Simplicity is a Feature: A relay should be as easy to run as a hello-world script.
AGPLv3. See LICENSE for details.