Relays as Routers: Keeping Nostr Extensions Decentralized

First, a product announcement.

Coracle now supports connection multiplexing, which can reduce bandwidth usage by over 90% depending on how many relays you use. It's opt-in for now, but you can set it up by going to Settings and entering wss://multiplextr.coracle.social as your "Multiplextr URL".

You can check out the source code and self-host the library using this link. If you're a dev and want to add client support for multiplextr, the library I built to support this use case might be of use.

Now, on to your regularly scheduled blog post.

Now for something completely different

The above announcement isn't irrelevant to what I want to talk about in this post, which is (broadly) the question of "how can Nostr remain decentralized and still support advanced functionality?"

This is probably the most common question articulated among devs and enthusiasts - is search centralizing? What about recommendation engines? COUNT? Analytics? The answer is yes, and responses range from "it'll be fine" to "nostr is already captured".

For my part, I'm not sure if this problem can be solved. Already we have a browser wars dynamic emerging among clients, and business models based on proprietary services and advertising have been publicly considered. For the record, I don't think conventional business models are necessarily bad. The world works this way for a reason and Nostr isn't going to change that by default.

Nevertheless, I want to see a new internet emerge where my attention belongs to me, and I'm not beholden to massive companies who don't give a rip about me. As a result, much of the work I've put into Coracle hasn't gone into fun features, but into things I think will help realize the vision of Nostr. This gives me FOMO as I watch others' progress, but if I don't stay focused on my vision for Nostr, what am I even doing?

I should be clear that this is not a judgment on the motivations of others, building for fun and profit is just as legitimate as building to idealistically realize the best of all Nostrs. However, I would say that it is every developer's duty to keep in mind that what we're trying to accomplish here is not a web2 clone.

Two, and only two options

With all that said, let's get into the meat of the problem. There's a false dichotomy floating around out there that we have two options for adding server-side functionality to the nostr ecosystem. Option 1: pack all required functionality into relays, eliminating the "dumb relay" model, and making it extremely difficult to run a relay. Option 2: keep relays dumb and the protocol minimal, allowing indexers, search engines, and recommendation services (which I'll collectively call "extensions" here) to profit by solving advanced use cases.

Both alternatives are obviously deficient. Relays need to be something hobbyists can run; requiring relays to fold in a recommendation engine or search index makes that much harder, and for every feature required, proprietary solutions will be able to build a bigger moat.

On the other hand, proprietary extensions will not bother to interoperate. This will result in an app-store-like landscape of competing extensions, which will redirect developer and user attention away from relays to extensions. If nostr is to succeed, relays must remain an important first-class concept. Aggregators and indexers that gloss over the differences between relays destroy much of the value an individual relay has to offer.

In either case, some components of the network will become too sophisticated for a layman to deploy. The only alternative is for a few professionals to take up the slack and grow their service as a business. But I think there's a way to squeeze between the horns of the dilemma.

It's all about routing

It seems to me that most people prefer the "extension" model of scaling functionality of Nostr as a pragmatic, market-driven alternative to the impossibility of requiring all relays to support all possible features. And I agree, the folks developing and operating more sophisticated tools should be compensated for their hard work.

The real problem with this approach is that not that extensions are competitive and specialized, but that they obscure the importance of relays by becoming gatekeepers for data by providing additional functionality. If a client or user has to select a search engine and ask it to return results for a given relay, they have given that search engine control over their results, when their trust really should be placed in the relay itself.

(I will say as an aside, that there are scenarios when the gatekeeper approach does make sense, like when a user wants to "bring his own algorithm". But this should be something a user can opt-in to, not a default requirement for accessing the underlying protocol.)

Here's my proposal: instead of requiring users to trust some non-standard extension to make decisions for them, flip the script and make relays the gatekeepers instead. With this approach, the addition of a single feature can open the door for relays to support any extension at no additional cost.

One of the most exciting aspects of Nostr is the redundancy relays provide. With Nostr, you don't need to trust a single entity to store your data for you! Why should you trust a single gatekeeper to route you to that data? Relays don't need to provide search or recommendations or indexing functionality directly, they can simply send you to a third-party extension they deem trustworthy.

This approach allows extensions to piggy-back on the trust already endowed in relays by end users. By allowing relays that are already aligned with end users to broker connections with extensions, they form a circuit breaker for delegated trust. This is more convenient for end users, and makes it easier to switch extensions if needed, since relay operators are more likely to have their finger on the pulse than end users.

It also enables cleaner business relationships. Instead of asking clients to create custom integrations with particular extensions leading to vendor lock-in, an extension provider can implement a common interface and sell to relays instead by offering to index their particular data set.

With this model, relays have the flexibility to either provide their own advanced functionality or delegate it to someone else, reducing the functionality gap that would otherwise emerge with thick relays without removing the ability for extension service providers to run a business, all the while keeping users and clients focused on interacting with relay operators rather than non-standard extensions.

Making it happen

The difficulty with this of course is that add-on services need to be identifiable based on functionality, and they must be interoperable. This means that their functionality must be described by some protocol (whether the core Nostr protocol or an addition to it), rather than by proprietary extensions. There will be extensions that are too complex or special-purpose to fit into this model, or for whom interoperability doesn't matter. That's ok. But for the rest, the work of specifying extensions will pay off in the long run.

This routing layer might take a variety of forms - I've already proposed an addition to to NIP 11 for service recommendations. Clients would look up what add-ons their relays recommend, then follow those recommendations to find a service that supports their requirements.

It also occurs to me having written my multiplexer relay this week (and here we come full circle) that it would be trivially easy for relays to proxy certain types of requests. So for example, a relay might fulfill REQs itself, but pass SEARCH requests on to a third-party extension and relay the result to the end user.

In either case though, a well-behaved client could get all the functionality desired, for all of the data required, without compomising the brilliant trust model fiatjaf came up with.

Conclusion

I think this is a very important problem to solve, and I think relay-sponsored extension recommendations/routing is a very good way to do it. So, please comment with criticisms! And if you agree with me, and want to see something like this become the standard, comment on my pull request.