Skip to content

Connecting

This section will briefly explain the different mechanmisms through which NDK can connect to relays.

Connecting

Connecting to relays in itself is super easy.

ts
// Import the package
import NDK from "@nostr-dev-kit/ndk";

// ... set up signer, specify relays, ...

await ndk.connect(); 

On connection changes NDK will emit a number of connection events.

Connection types

TIP

Because NOSTR is decentralized and comprised of thousands of relays, it's important to read up on the advised ways of connecting to relays. We advise you to use the "Outbox Model" in addition or as a replacement for specifying explicit relays.

Specific Relays

The simplest way to get NDK to connect to relays is to specify them:

ts
// Import the package
import NDK from "@nostr-dev-kit/ndk";

// Create a new NDK instance with explicit relays
const ndk = new NDK({
    explicitRelayUrls: ["wss://relay.damus.io", "wss://nos.lol", "wss://relay.nostr.band"],
});

// Now connect to specified relays
await ndk.connect();

Make sure to wait for the connect() promise to resolve before using NDK after which you can start interacting with relays.

Explicit relays can also be added using the addExplicitRelay() method.

ts
// Import the package
import NDK from "@nostr-dev-kit/ndk";

// Create a new NDK instance with explicit relays
const ndk = new NDK();

ndk.addExplicitRelay("wss://a.relay");
ndk.addExplicitRelay("wss://another.relay");

// Now connect to specified relays
await ndk.connect();

User preferred relays

A signer is used to sign events and tells NDK about your pubkey and related settings. Once you link up a signer and you have autoConnectUserRelays enabled (on by default) NDK will fetch your kind:10002 event (NIP-65) and add discovered relays specified to a 2nd pool of connected relays.

ts
// Import NDK + NIP07 signer
import NDK, { NDKNip07Signer } from "@nostr-dev-kit/ndk";

// Create a new NDK instance with signer
// (provided the signer implements the getRelays() method)
const nip07signer = new NDKNip07Signer();
const ndk = new NDK({ signer: nip07signer });

Outbox Model

Outbox (previously known as the Gossip Model) is a more elaborate way of dynamically connecting to relays based on who you are interacting with. More about the outbox model.

The outbox model works similarly to the web/RSS model:

  • Outbox Relays: You post your content to your own designated relays
  • Inbox Relays: You designate relays where you want to receive messages
  • Dynamic Discovery: Clients discover and connect to relays based on where users actually post

The protocol is formalized in (NIP-65), which defines:

  • kind:10002 events: Relay list metadata containing read/write relay preferences
  • Relay tags: "r" tags with optional "read"/"write" markers
  • Fallback to Kind 3: Contact list events can contain relay information in their content

By enabling enableOutboxModel (off by default) NDK will add an extra outboxPool to the ndk pool AND (@TODO Explain)

https://primal.net/e/nevent1qqs2txvkjpa6fdlhxdtqmyk2tzzchpaa4vrfgx7h20539u5k9lzgqwgfjnlen

Dev Write Relays

During local development you might want to specify a list of relays to write to. THis can be done by using devWriteRelayUrls which will

ts
import NDK from "@nostr-dev-kit/ndk";

const ndk = new NDK({
    devWriteRelayUrls: ["wss://staging.relay", "wss://another.test.relay"],
});

await ndk.connect();

This will write new events to those relays only. Note that if you have provided relays in explicitRelayUrls these will also be used to write events to.

Relay Sets

Under the hood NDK uses different sets of relays to send and receive messages. You can tap into that pool logic by using the NDKPool class.

ts
import NDK, { NDKPool, NDKRelay } from "@nostr-dev-kit/ndk";

const ndk = new NDK();

const largeRelays = new NDKPool([`wss://relay.damus.io`, "wss://premium.primal.net"], ndk);
largeRelays.addRelay(new NDKRelay("wss://nos.lol", undefined, ndk));

const nicheRelays = new NDKPool([`wss://asad`, "wss://premisadasdum.primal.net"], ndk);

nicheRelays.connect();

ndk.pools.length; // 2

Note that if you have outbox enabled you will have an extra pool in the ndk.pools array reserved for user provided relays.

Authentication

(NIP-42) defines that relays can request authentication from clients. NDK uses an NDKAuthPolicy callback to provide a way to handle authentication requests.

  • Relays can have specific NDKAuthPolicy functions.
  • NDK can be configured with a default relayAuthDefaultPolicy function.
  • NDK provides some generic policies:
    • NDKAuthPolicies.signIn: Authenticate to the relay (using the ndk.signer signer).
    • NDKAuthPolicies.disconnect: Immediately disconnect from the relay if asked to authenticate.
ts
import NDK, { NDKRelayAuthPolicies } from "@nostr-dev-kit/ndk";

const ndk = new NDK();
ndk.addExplicitRelay("wss://relay.f7z.io", NDKRelayAuthPolicies.signIn({ ndk }));

Clients should typically allow their users to choose where to authenticate. This can be accomplished by returning the decision the user made from the NDKAuthPolicy function.

ts
import NDK, {NDKRelayAuthPolicies} from "@nostr-dev-kit/ndk";

const ndk = new NDK();
ndk.relayAuthDefaultPolicy = (relay: NDKRelay) => {
    return confirm(`Authenticate to ${relay.url}?`);
};

Connection Events

There are a number of events you can hook into to get information about relay connection status

ts
import NDK, { type NDKRelay } from "@nostr-dev-kit/ndk";

// Create a new NDK instance with explicit relays
const ndk = new NDK({
    explicitRelayUrls: ["wss://a.relay", "wss://another.relay"],
});

// Main pool events
ndk.pool.on("relay:connecting", (relay: NDKRelay) => {
    console.log(`⟳ [Main Pool] Connecting to relay: ${relay.url}`);
});

ndk.pool.on("relay:connect", (relay: NDKRelay) => {
    console.log(`✓ [Main Pool] Connected to relay: ${relay.url}`);
});

ndk.pool.on("relay:disconnect", (relay: NDKRelay) => {
    console.log(`✗ [Main Pool] Disconnected from relay: ${relay.url}`);
});

Code Snippets

More snippets and examples can be found in the snippets directory