So I'm just at the tail end of a project where I'm attempting to build a collaborative text editor, and it's been absolute hell. I figured it would be a tricky problem, but I had no idea how far down the rabbit hole goes. I kept thinking, gosh, there's gotta be a backend service that bakes this in, if there isn't it would be a great business opportunity.
I almost want to scrap all of my code and move it to Supabase. Congrats to the team on this launch, very cool.
edit: actually, after thinking it through, I'm not clear on what Supabase is calling multiplayer. Presence is one thing, but when I think multiplayer, I'm thinking conflict resolution. Is this an OT/CRDT implementation? Or is it just presence?
One thing that... might be useful depending on what exactly you're building here is https://hocuspocus.dev, which is an incredibly easy to use server for Y.js.
It's written by the team behind https://tiptap.dev, which is an amazing WYSIWYG text editor, but HocusPocus does a great job of syncing state of a variety of WYSIWYG editors out of the box. Getting the server running is a couple of minutes worth of work and scaling it is quite easy.
In addition to editor state, it also has built-in support for 'Awareness' (info on current users), as well as any other Y.js datatype, including other things with a bridge into Y.js.
Related to this is also an example from ProseMirror (which TipTap uses as the editing component) [0][1]
I'm not completely sure, but I think at ProseMirror they're using Yjs [2] for the collaborative editing part. If not, checking out Yjs is worth it in and of itself.
> Yjs is a CRDT implementation that exposes its internal data structure as shared types. Shared types are common data types like Map or Array with superpowers: changes are automatically distributed to other peers and merged without merge conflicts.
> Yjs is network agnostic (p2p!), supports many existing rich text editors, offline editing, version snapshots, undo/redo and shared cursors. It scales well with an unlimited number of users and is well suited for even large documents.
> Conflict-free replicated data types (CRDT) for collaborative editing are an alternative approach to operational transformation (OT). [3]
OT was what Google Wave was based on and I think current colab editing in Google Docs and other of their office products use this.
ProseMirror has its own OT system developed by its lead developer. However the developer behind Yjs has created Yjs bindings for it that are first class!
The team behind TipTap (built on top of ProseMirror), created the Hocuspocus server backend for Yjs and collaborative text editing.
Ha, that's good to know -- I've been enjoying using Vowel and was wondering what the in-call notes editor was powered by. Vowel is really slick too -- nice job! :)
I'm using TipTap actually, but decided not to go with hocuspocus since it's in beta (at least that's how they position it).
edit: also, I couldn't get a good look at their documentation outside of the paywall, so I have no idea how they implement the backend. It's important, because I need to persist my documents as html strings, not as y docs.
Just so you know, I've used it since the early part of this year and found it to be robust and fully-featured (most functionality comes from Y.js after all), but definitely defer to them on how ready they consider it. :)
+1 for tiptap, and yjs, used both to build https://www.buildmemo.com 's collaborative editor. Did not use hocuspocus but found it trivial to implement our own node ws backend.
For a collaborative text editor, you need two things: (1) a full-stack system that maintains a running list of data events such that everyone sees everyone else's events eventually, and (2) frontend code that adapts that set of events, along with your text cursor position and current changes, into a cohesive view of a document at any moment in time.
Supabase and Replicache can absolutely help with (1). But for (2) you will need OT or CRDT.
Quill Deltas are a very interesting concept, I used Quill myself along with Supabase for realtime sharing (not collaboration) of text and it was almost a breeze.
No. All you have to do to use Replicache is embed the `replicache` npm package in your client-side code, and implement the expected REST interface on your server: https://doc.replicache.dev/guide/intro
It’s just a fact to consider in tradeoffs. There are several economic models that support tool businesses, or returns for investors. Please don’t take offense at noting which of those several valid approaches
Not offended. Our team has a long history in open source and have seen both the triumphs and challenges over the years. It's very difficult to build a sustainable client-side open source tool without some other business off to the side that supports it (example: nextjs/vercel).
I like the simplicity and clarity of just directly charging for the valuable thing. Nothing wrong with the other models, they just aren't for us.
Definitely feel your pain. We did a full OT implementation for our startup [0] and it was a beast. We based it on Slate.js which has a nice concept of operations that maps nicely to OT, but it was still a lot of work to get it working well (and there are still rough edges we try to improve all of the time). We did base it on Postgres in the backend so really looking forward to what the Supabase team comes up with going forward and seeing if they can help us delete some complex code :-)
Happy to have a chat on collaborative editing anytime if that'd be helpful (email in profile).
It’s broadcast and presence they have released, both building blocks for multiplayer. It’s unfortunate that HN rules meant a mods changed the title to the blog posts title. I had gone with a slightly edited (for length) sentence from the second paragraph as I thought it was clearer:
… general availability of Realtime's multiplayer features, Broadcast and Presence.
Pricing is still tbd unfortunately. Currently every project gets these features with some limitations:
- 25 concurrent channels
- 25 channel joins per second
- 200 concurrent connections
- 100 broadcast messages per second avg over 60 seconds (not including db changes) (aka 6,000 per minute rolling)
I think these are probably pretty close to where we'll land for free projects. They can be changed per project so if you (or anyone) needs a limit increased in the short term we can do that.
I haven't documented it yet, but my serverless board game platform supports collaborative text editing. I'm using Codemirror 6 which has a very simple operational transform scheme, and I baked Codemirror's OT scheme into my back-end. It works great, but this was because I had all the realtime stuff sorted out (connection management, multiplexing, etc...)
I can definitely see how a company built on Elixir, like Supabase, would offer this as part of their product.
Phoenix Framework gives you presence and CDRTs out of the box. I’m not sure if they’re also using Phoenix, but there’s a well-known, heavily used open source solution for the core of this offering and I’d be shocked if they didn’t at least study and/or borrow from it.
Edit: yep, according to the page they’re advised by Chris McCord, the creator of Phoenix.
Fluid Framework looks interesting. Since it's open source you can either use a cloud service (Azure Fluid Relay) or run it on Kubernetes with Routerlicious.
https://fluidframework.com/
That sounds like a stack that should be up for the job. Used these myself and found making a collaborative editer with those quite a breeze actually. What issues do you have with them? Or did it just take a long time before arriving at that combination?
That combination kinda came by default, since I opted to use TipTap: https://tiptap.dev/
My real trouble is the fact that this is an existing application, with hundreds of thousands of pre-existing documents, all stored as html strings. I've been trying to extract the html on the server, but it's incredibly difficult. I've actually given up for the time being, and using a hacky workaround.
we're excited about this release - it adds a few neat features to our Realtime server[0]. For those who don't read the post (it's quite long), our Realtime server was initially built for subscribing to Postgres changes via websockets. We've added Broadcast functionality (for "ephemeral" messages that don't need to be persisted to Postgres) and Presence (similar to Broadcasts, but it retains an eventually-consistent state between users).
We were planning a larger write-up with all the technical details but it became a bit long. Some highlights:
- Realtime is built with Elixir an Phoenix[1]
- We've moved to a single, global cluster
- We're using `Phoenix.Tracker` to globally distribute the Erlang PIDs of all of our Postgres connections. This guarantees there is only a single connection to each database.
- We've implemented a "leaky-bucket" rate-limiter using Erlang's `:counters` module[3] for "per tenant" rate-limiting. We'll move this to a global rate-limiter in the future
- We're currently seeing ~2000 concurrent connected users - it will be interesting to see what this spikes up to now that this is on HN
It's still in heavy development, and we'll make sure to detail all the choices we take as we continue solve problems. A few of the Realtime team will be here answer questions - @chasers, @wenbo, @abc3erl.
I have almost zero coding experience. Seriously, I've read a couple of books and I've taken a couple of MOOCs and that is about it. I've never 'launched' any project of my own, and I have zero front-end or back-end experience.
I say that because I just used Supabase for the first time, and I was able to build and launch the Slack clone in ~15 minutes. Seriously cool. Thank you for sharing
Yeah the database ultimately guarantees that. This lets us distribute the fact that a connection exists (in the form of a PID) so that we don't have to go back to the db on every connection request. This helps quite a bit in the case of a lot of connections coming in very quickly, especially when those connections are geographically far from the database or the database is under load from some other system.
If no connection exists yet, you're right, two connections could try to establish themselves at the same time. In which case, whoever gets to the db first wins. But then the loser is still connected to PubSub, so they'll now start getting changes just the same.
What are the chances of an official C# library being in the works? I think this would greatly fill the needs for unity devs. I use firebase on almost all game backends because of how quickly I can get set up with auth and a db.
I used supabase in my latest project and it served my needs but there were a few difficulties to overcome. The greatest shortcoming was the lack of real time support (C#), and I had to do everything via REST api.
I am planning on publishing the game as OSS and making some learning videos about it
They won't support the functionality we outline in our blog post yet (we are still figuring it out on our official JS libraries), but I'll send him your message.
As an aside, if anyone is reading this and wants to help maintain the C# libraries, please reach out.
LOVE Supabase. Building a project over the last several months for a client and very excited to launch the beta soon. Thanks for all you are doing...very exciting stuff.
Creating dev and staging environments is a feature that I am most looking forward to. Hopefully that is on the road map.
Hey Kiwi, any chance of getting temporal.io style features for supabase edge functions? would love to have a one-stop-shop solution for all my real and not-real time needs.
Temporal has done an incredible job of ensuring there will be no side-effects (even with external systems), so I doubt we'll be able to do something as extensive as they have. That said, we will probably build a simple Postgres queue/workflow engine (similar to pgboss[0]). It will live in the Postgres database (as an extension), but will be nicely integrated with Edge Functions. We haven't started this yet, so I don't have any timelines.
The reason we paused it was the realisation that it's far more powerful to co-locate this sort of product with the data. In this case, Workflows would be more powerful as a Postgres extension - you can store the workflows into your database, create them using SQL, and the workflows would have direct access to your operational data. We'll probably re-write this using pgx[0] at some stage (if anyone is reading this and wants to attempt this, please reach out).
Really exciting! I’ve been checking your blog every couple weeks waiting for this release.
Does the global cluster architecture make it much harder to self-host supabase? Not that I plan to, but having the promise of portability is really important.
It would be great to see monitoring of this thing under load – I mean the Postgres part of it, how it's loaded, how many connections used, query analysis, etc.
Isn't the whole supabase open source? Oh actually you mean, you want to run this without supabase?
The code is already open source, and anyone can extract it into a more reusable package. And it's developed in the open, anyone can fork or send PRs or anything. That's what open sourcing a piece of code is really about.
Yeah, I already extracted the WAL listening bit out (which is now far behind the realtime changes). And for that reason would rather have those pieces as individual packages for the wider Elixir community and so that it's easier to contribute back.
I can speak some to the Elixir tech it is built on. It should be low, even with load. The Erlang VM is very good with concurrency and keeping latencies consistent and low.
The presence feature could be slower since that propagates a bit more complexly than the broadcasts would.
Of course the latency can go up with load but it shouldn't get very spiky thanks to the preemptive multitasking.
This is really neat, I have been keeping an eye on Supabase, this (presence) is the feature that will finally push me to build a side project with it. I have one in mind.
Anyone from Supabase here, do you have any plans to build in support for CRDT toolkits such as Yjs or AutoMerge for these features? It would make working with them so much easer if there was a plug and play backend.
The one other thing I would love to see next from them is an offline sync product, so you could partially sync a users dataset to their device and save back any changes later (bonus points for then combing that with CRDTs). Maybe the WASM Postgres yesterday [0] could be a foundation for such a product.
It's definitely something we'll support (we mention it briefly in the blog post). We'll extend this service so that it works well with WebRTC, and we have a few ideas for making it easy for development.
> Maybe the WASM Postgres yesterday
This was mind-blowing! Very cool what the crunchy team have done there. It would be awesome to replicate from a remote Postgres database to a "per-user" database to the browser. I think WASM support needs to improve before it can become generally useful for offline-sync, but the tech seems withing reach.
We're working on various ideas for offline-sync, but the Realtime server will be central to whatever implementation we land on.
Any idea if Realtime might support Postgres streaming replication in the future? We were incredibly excited to use Realtime with TimescaleDB, but couldn't get it working.
Realtime uses logical replication, and from your link it looks like it should work with Timescale (although not recommended):
> Using logical replication with TimescaleDB is not recommended, as it requires schema synchronization between the primary and replica nodes and replicating partition root tables, which are not currently supported.
As long as logical replication is supported, this won't be an issue for Realtime because the purpose is to receive data changes (which come in a JSON format) and the end-user doesn't need to persist schema modifications.
> but couldn't get it working
If you send me some error logs, I can take a look or forward to one of the team.
> support Postgres streaming replication
This is the first time I've heard it requested - I don't think it's something we'd do unless there was a good reason and strong demand. If we were to do any work in this direction we'd prefer to try contribute DDL streaming to PostgreSQL's logical streaming. We've been thinking about this for a while (Michel has built metagration - https://github.com/michelp/metagration which has prompted a few ideas for core patches)
> If you send me some error logs, I can take a look or forward to one of the team.
I really appreciate the offer. I don't have the logs handy unfortunately and haven't been interacting with the Timescale instance in a few months. If I move back to that side of things I most definitely will take you up on that.
For what it's worth, I don't think the error was in running or connecting to Realtime; rather, I think what happened is there were duplicate, missing, or truncated messages. Thinking on it some more, I think TimescaleDB is using multiple tables under the hood for the tables they expose. Unfortunately, it's out of my depth of Postgres knowledge right now, so I can't tell you more
I previously experimented with building an offline syncing CRDT db using Pouch/CouchDB and combining it with Yjs for automatic conflict resolution. But Postgres would be so much better as the foundation. If only I had time it is something I would love to work on…
I should have been more clear - when I say "working on", it means "debating internally what would be the best long-term strategy" (from a technical POV).
But yes, optimistic updates is one of the requirements. In the meantime, if you need something great, I can recommend Replicache and WatermelonDB - both are excellent.
Agree, I would love to see CRDT (or related) multiplayer resolution as that's a big time sink for a lot of new collaboration product ideas around dashboards, documents, spreadsheets, online games, mindmaps, and flows (like figma).
Yes, you can self host and everything is open source (including the Dashboard[0]). Everything is either MIT, Apache2, or PostgreSQL licensed.
> difference between Supabase open-source and the paid versions
On the paid version we handle some of additional database management (like daily backups, PITR, etc). These are technically available for self-hosting too, because the database is just a Postgres database, but I point it out here because it's not something you'll get "out of the box" from the Docker setup.
Our philosophy with open source is "offer everything" and then charge for usage. There aren't any features completely gated. Our Enterprise plan just adds additional SLAs and support packages for our cloud platform.
In addition to the self-hosting docs you've linked, in our GitHub you can find the Docker files[0] and some community-developed self-hosting strategies [2]
I've been watching Supabase for a long time and wanted to try it out. I had the chance to use it in a couple of projects that I started, but I feared it will cause me problems down the road, and eventually I decided to build the backend services myself. I'm comfortable with NestJS which is not supported in Deno, and I felt that my productivity would've been harmed if I picked up Supabase. But definitely I have to build up confidence by starting a personal project. Is there anyone who uses Supabase in production? Do you have any feedback?
I don't get the advantage of using supabase or things like it. It feels like you are basically relying on a third party to do the work for you and you are paying them to do it.
Doesn't seem portable at all. If you make your own code, you can move it wherever you want in whatever system you want. It seems like if you use this product, it will get you stuck in that environment and if you need to upgrade, then you are going to have to do the work later on anyways.
What exactly is so great about this product? I'm not saying its bad, I'm just not fully understanding the advantages of using it?
Why would someone want to use this over something like a framework for the backend (that is free) and a database they want and then host it wherever they want? I don't really get why someone who knows how to code would want to pay extra money to build a backend.
If you "know how to code" then why did you buy a laptop with an operating system that someone else wrote instead of building your own laptop and writing your own operating system for it so that you have more portability and control?
You're going to have to pay to host your Rails/Django/Whatever app anyway, and you're also going to have to pay for a hosted Postgres solution, so why not just get them both in one deal and then also dispense with the need for a bunch of Rails code thanks to the auth and REST api that is built in to Supabase.
Saves me a ton of time to use Supabase or something similar — as a single developer / "indie hacker" this frees up time to work on other things, or for more naps :)
Also, I don't have to worry about my code being terrible, either.
Is server authroity and broadcast permissions handled or left as a task for the user? Can channels be locked down to a list of users? Can users be kicked from a channel? Is message spam/flooding/DDOSing users in a channel protected?
Quickly skimming the docs, I don't see any examples of this.
Server authority and some of this security can be added app level but I think the message throttling needs to be built in if its going to support any kind of pvp/untrusted peer scenario.
> Is server authroity and broadcast permissions handled or left as a task for the user? Can channels be locked down to a list of users?
Broadcast permissions is currently not handled by the server and left to the developer to implement. We have discussed this internally and will prioritize Broadcast authorization accordingly because we've gotten feedback about this from a number of developers.
> Can users be kicked from a channel?
Not at the moment but again we've gotten feedback about this as well and will prioritize it.
> Is message spam/flooding/DDOSing users in a channel protected?
We have built rate limiting and other protections so bad actors don't affect the good in the cluster. A colleague of mine posted these limitations of Supabase Realtime to prevent abuse: https://news.ycombinator.com/item?id=32511586.
This is intresting. I've been thinking about using the web for more multiplayer games for a while, and a tool like this is more or less exactly what I'm looking for. Noone wants to make netcode.
I have a multiplayer web game also on SvelteKit but I created my own little sockets server with Go and Redis streams running on a tiny k8s cluster. I'm curious how much traffic you're getting and how much it costs to run it.
Congrats on the launch and hitting HN's front page.
Do you mind if I ask how your example site (multiplayer.dev) scaled?
I'm super curious about realtime multiplayer solutions (and I don't think I'm alone). But I find a great lack of info on what running this kind of app would cost. I come from the old-school hold-no-state, request->response->gtfo mentality, and I always have the _feeling_ that it'd be expensive to scale.
Not just holding the websocket open, but how much effort do you expend parsing the WAL? How chatty is that kind of persistence mechanism? What other 'gotchas' are there etc.
I'd love nothing more than to dispel that vague feeling with data.
I know it wouldn't come close to a full performance analysis, but throwing a few datapoints on a chart would help get a ballpark idea and tune my hype->action conversion.
I could nail down a pile of questions, but I'm sure you know better than I how to measure your own systems. But roughly I'm wondering:
- how many users did you have?
- how much traffic did you get?
- how much would/did it cost to host on supabase?
- how much resources did the database/realtime components consume?
Congrats again on the launch and have a nice weekend.
> Supabase is an open source Firebase alternative. Start your project with a Postgres Database, Authentication, instant APIs, Realtime subscriptions and Storage.
We started developing Realtime: Multiplayer version many months ago in a private repo just to experiment with Phoenix's Broadcast and Presence and over time we just added to it.
We plan to move all the code over to https://github.com/supabase/realtime in the next couple of weeks and you'll be able to see the code in its entirety.
Yes, we are - but no ETA yet (sorry, we've been focused on the infrastructure).
There are some community-developed libraries here: https://github.com/supabase-community. We sponsor developers to maintain these - at some point we'll hire someone to work full-time on these (and we'll start with iOS/Android)
FYI multiplayer.dev breaks the browser back button. At least on mobile safari. Is that a glitch in that demo specifically? Or is it a supabase realtime glitch?
I imagine it's a glitch caused by the way the demo "redirects" a user to a room. Probably you hit back and then get redirected again. Sorry about that - it's not intentional. I'll let the team know.
That back button glitch is specific to the demo. We had to do a few redirects based on Presence sync and load balancing each room. I'm sure there's a better way of doing it and will seek to improve it when I update it. Sorry about that!
At the top their homepage (which admittedly doesn’t have a link to it other than the logo):
> Supabase is an open source Firebase alternative. Start your project with a Postgres Database, Authentication, instant APIs, Realtime subscriptions and Storage.
Client will seek to continuously reconnect to the WebSocket when there's a connection issue and server must receive at least one heartbeat in a 60 second window; otherwise it will clean up the WebSocket connection.
We built Supabase Realtime on top of Phoenix Channel, and along with our clients, handles unreliable network connections gracefully, including on mobile.
"Phoenix uses an at-most-once strategy when sending messages to clients. If the client is offline and misses the message, Phoenix won't resend it. Phoenix doesn't persist messages on the server. If the server restarts, unsent messages will be gone. If our application needs stronger guarantees around message delivery, we'll need to write that code ourselves. Common approaches involve persisting messages on the server and having clients request missing messages. For an example, see Chris McCord's Phoenix training: client code and server code."
queues either end. Clients are given a session ID, server (and client) replays missing messages on reconnect. It's the only way to achieve causal consistency, which is what you need for a sane programming model
In safari, with the multiplayer.dev demo, my own chat bubble is terribly unsmooth, when I move my mouse. It almost looks like it's getting a local and, slightly delayed, remote position update, and they're fighting.
I'm probably not the only one who thought this was about Supaplex https://supaplex.me/ - .a popular extended boulderdash clone - because of the term 'Multiplayer' before clicking the link.
For those who didn't know, the dos game is now freeware and there is a reverse engineered open source multi-platform port. There is no multiplayer mod, yet.
I almost want to scrap all of my code and move it to Supabase. Congrats to the team on this launch, very cool.
edit: actually, after thinking it through, I'm not clear on what Supabase is calling multiplayer. Presence is one thing, but when I think multiplayer, I'm thinking conflict resolution. Is this an OT/CRDT implementation? Or is it just presence?