Leaflet is open source — view the code here on GitHub.
We picked our tech stack to let us quickly iterate and build really really rich interfaces while keeping everything fast. Most of our choices are fairly boring, with a couple spices thrown in:
The Framework: Next.js (and hence, React)
We've used NextJS for a long time. While it definitely isn't all smooth sailing, it's incredibly robust and reliable, and has a lot of flexibility. React Server Components, while something we (and the ecosystem) are still figuring out how to make the most of, lets us get fast SSR with minimal code duplication.
We use server actions a bunch, but also often use our own little RPC client with a route handler. Still figuring out how to make the best use of `revalidatePath` and `revalidateTag`.
A major refactor we need to do is moving the majority of the backend related to publications to XRPC, so that it too can be defined with lexicons and built on by the wider ecosystem.
The Database: Supabase (i.e Postgres in a fancy coat)
I like that Supabase basically just wraps Postgres, and I really appreciate its wrapping. Nice local development, easy type generation, migrations, and access over HTTP all make my life easier basically every day.
One quirk is that the vast majority of our data is stored in two big tables. We model our application data (things like the blocks in a document, themes, etc) as a graph of entities, which are just unique identifiers, and facts about them, which can be relationships to other entities.
The Host: Vercel
We've also been using Vercel for ages. They're not the most flexible platform but the combination of instant deploys, analytics, observability, and all the little things really makes them a no brainer (at our scale).
One area I really appreciated: when we were implementing custom domains, initially for individual leaflets and then for publications, it was dead simple to manage the whole life cycle, and define the routing logic directly in our code base.
The Editor: Prosemirror and Replicache
There are two main parts to the Leaflet editor: Prosemirror, which basically gives us a beautiful API for a rich text editor, and Replicache, which enables us to have dead simple sync and optimistic updates everywhere in the app. We stitch the two together and enable proper collaborative editing with YJS.
One way we differ from your average Prosemirror implementation is we have our own data structure and editor for managing blocks, and Prosemirror instances are only for an individual text block. This let's us more easily create new block types, do complicated queries, and generally have the same data model everywhere.
And of course: ATProto!
It's actually been a dream to build in the ATProto ecosystem. It's OAuth implementation is not only very unique in that it provides a "permissionless" identity service, it also has the best local development story I've ever seen.
Lexicons are also very ergonomic to write and type generation based on them works great.
And of course at the heart of it is the PDS => Firehose => Appview => FrontEnd loop, which is clean and simple, and enables all the cool things we've already seen in the bluesky ecosystem!
We run our firehose ingestor on Disco, a really great kinda "build-your-own-cloud" platform. It lets you run multiple services on a single computer, and easily deploy and scale them, as well as communicate between them. We also use it to run our feed generator!
We're currently creating records for publications, posts, and follows, and reading from bluesky for profile data. We'll soon be also picking up mentions of Leaflet publications in bluesky posts, and allowing Leaflet publications to quote each other as well as bluesky posts!
It's pretty incredible that we have a software stack that makes this kind of interoperability not only possible but honestly kind of easy. We're barely getting started with the kinds of hyper-linked applications it will enable.