 All right, I'm going to go ahead and get started right away. I got a lot to get through. I'm really excited to be here at WasmCon to talk about SQLite in Wasm. So yeah, let's just jump right into it. First, I want to just tell you a little bit about myself. I love offline-first applications. I think offline-first applications are amazing. They're amazing to use. They feel really great. If you aren't super familiar with this term, you aren't sure exactly what offline-first application is. This is how I sort of define it. Basically, something that is designed to function effectively without the internet connection. But critically, when you have the internet connection, when you get back to being connected, they're able to synchronize their state that was mutated locally with the server. And so offline-first apps enable this really amazing user experience. The most sort of notable one of this group, I would say, is the email clients. Pretty much every email client that isn't entirely in the web browser, and even ones that are in the rem browser, are offline-first. When you go to create an email, you don't really expect to sit there and wait for the server to load. You're happy. You can move on. You can write a draft. You can queue it. And it'll be sent at some point in the future. So offline-first apps are everywhere. However, sorry, they're everywhere. And they give you all these amazing features. No latency. So because you have this data model that's running entirely on the client side, you have essentially optimistic mutations. Things happen right away. When you click a button, you just get the result. And this leads to a great user experience. In addition, because they have this data model that's designed to asynchronously work with a server, they're very, very reliable. Like if you have an offline-first app on your phone, you know that if you open it up on the subway when you're underground, you know it's just going to work. And this is different than an app that requires the internet. You're going to be sitting there waiting for a loading spinner. It's going to be a really bad experience. So they're very reliable. And finally, and the thing that I find most counter intuitive about an app that's built to be offline-first is that offline-first apps automatically have real-time collaboration built in. And the reason for it is because to build an offline-first app, you have to build a data model that you can do this asynchronous synchronization routine. And that same functionality is needed for real-time collaborative applications. So you might ask, why aren't all apps offline-first? Like if these are such great ideas, why do we even have this distinction? Why don't we just call it an app? And well, it turns out that there's some problems with this. Like there's some complexity you have to deal with when you have an offline-first application. So these are just a couple of the major categories of problems you have to deal with. I'll point out conflict resolution as being one of the primary ones, which is if you have two users who are manipulating the same state in two different devices at the same time, but they're offline, and then they become online, you have to deal with that conflict. You have to decide what to do to resolve this. And that's a really hard problem. And not only that, but by the way, device storage is really hard when you aren't working with nice server-side storage that just works, and it's super fast, and it has lots of guarantees. When you're working with someone's iPhone, that they have like 1% disk remaining. And it's a different story. You have to be able to deal with that. So lots of problems. And because of this, existing offline-first solutions are really complicated. You have to actually understand this problem space pretty deeply to be able to write an offline-first application today. But I want to point out that databases are really complicated. Like if you think about how databases work internally, they're really hard. They have a lot of complex stuff that they're doing under the hood. But how many people who are using databases on a daily basis actually have to think and reason about how databases work at a low level? I think that databases have done a really fantastic job hiding this extreme complexity behind a relatively easy-to-use interface. And I think that we should start looking at ways in which we can do that in the offline-first space. So I'm building it. I decided that I have some ideas about how this could work. I'm excited enough about it. And I wanted to create something, my version of what I think this offline-first experience could look like. Today, I want to share my journey about building it. So this is going to be really, really deep technical talk about actually building this type of solution. And of course, this is a WASM conference. Obviously, WASM is going to play a really big role. And so I'm excited to share that with you. But before we jump into that journey, I just want to introduce myself. My name is Carl Severe. I've spent the last 10 years working at Single Store, working on databases. I'm currently an entrepreneur in residence at Amplify Partners, which is basically code for I'm in stealth. And I'm going to be launching a product soon. If you want to follow me and follow my journey more, I'm on Twitter. Yes, it's Twitter and not X. All right, so we've got a three-act plan. We've got plan, execution, and delivery. And let's jump right in. So the first thing I want to do is talk about the thing we're trying to build. Like whenever you're trying to build a complex system, like collaborative, eventually consistent, synchronized database in the browser, you need to have some kind of architectural plan. So this is what I started with a couple of months ago when I decided to kick off this project. I was like, all right, we want a database in the browser. We want some kind of magical asynchronous thing. We want a database in the server. I thought about it a bunch about are different ways of building this and different ways of writing these databases are they the same database? Are they different databases? And eventually I came to the conclusion that Wasm provides a really nice abstraction that if I can basically get my database core to be compiled to Wasm, I could run it in many different server backends and many different client frontends. I can very easily port it to something like a mobile app. All of these features would be much simpler if I had a nice standardized virtual machine representation like WebAssembly. So this is what I set out to build. So if we just start on the client side first. So everything on this slide is running on the edge like in the device. This is the SQL sync architecture and SQL sync is the name of the thing I'll be launching. I'll talk about that more later. But SQL sync architecture is very simple. When a user wants to do something like create a new to-do in some to-do list app, we just need to do two things. We're gonna store it in something called the timeline which is essentially the list of all the mutations that the user's done locally. And then we're gonna apply it to a SQLite running on the device. So relatively straightforward. I'm gonna hand wave a bunch of stuff here but this is the idea of what happens when you run a mutation on the client. So then what we have to do is we need to synchronize this to the server because we want to have multiple clients working with this system. So all the clients are going to asynchronously send their timeline of mutations up to the server. The server's gonna store that timeline and critically what the server's providing us is essentially a global ordering of mutations. I specifically am going with a central server model in my replication stack because it's a very simple and easy to reason about solution. It has trade-offs. There are other ways to do this with like peer-to-peer stacks and other things and complex things like CRDTs. But in this model it's very simple. There's no complexity. There's a single global order that we can look at in the server. The server takes that global order and applies those mutations to its own SQLite instance running onto the server side. And so now we have sort of multiple instances of SQLite. We have SQLite on the server with its sort of authoritative state where it's brought all the client states together. And then we have a bunch of individual client states on the client. So let's look at what happens on the client. So now the client has sort of a weird situation. It's replicated back from the server a new sort of snapshot of the real authoritative world where its mutations and mutations from many other clients have been incorporated into a single SQLite state. But it also has a bunch of local state that it's optimistically executed. And this is diverged state. It's a really bad situation to be in because under the hood SQLite source data is just like a bunch of B trees and like a page-based file format. It's not easy to just merge that directly. So how do we deal with this? How do we reconcile it? Well, turns out Git solved this a long time ago with Git rebase. And so we do the exact same thing. The first thing we do is we basically throw away all of our local changes and we delete all the mutations that we know have been transactionally applied to the server. How do we know this? Because SQL Sync stores some metadata about what mutations are applied transactionally in the actual snapshot that we replicate back to the client. So the SQL Sync knows deterministically exactly what set of mutations have been applied and which ones haven't. So the first thing we do is we throw away all the applied mutations. They've already been incorporated and we throw away our local state. But now we have a problem. We have a bunch of unapplied mutations that have potentially, that haven't yet been incorporated on the server. So how do we deal with that? Well, we just reapply them. SQLite's pretty fast and for the types of data models that I'm going for which is a relatively small data model running on the client, we can actually do this very quickly. And so the client can happily make progress rebasing itself periodically on the server to incorporate third party state. And you end up with a really simple replication model. I am hand waving a bunch of stuff but this is enough to get onto the core of this talk which is going to be talking about how to build this with Wasm and all the fancy stuff around that. All right, like to execution. The first thing I needed to do when I set out to build SQL Sync was compile SQLite to Wasm. That was the primary sort of, can I do this? And the answer is yes and actually I'm not the first person to do it. There's a lot of people who have done compile SQLite to Wasm and even the SQLite core team has compiled SQLite to Wasm. So fantastic, I'm already starting running. I don't have to do everything from scratch. So I started to investigate how people are compiling SQLite to Wasm. I started to play around with different ways. And the first thing I realized is that almost everyone who compiles SQLite to Wasm uses Inscripten. And I just want to say, Inscripten is an amazing tool. If you want to take like a completely normal vanilla C++ program or C program and just get it running in Wasm, it's gonna work. And the way it works is because it has so many batteries included. Like it even has a frickin P thread shrimp. Like that's amazing. And in some cases, that's exactly what you want. You just want something that just works. However, in my case, I had a relatively lightweight database engine which is SQLite. It's already an embedded library. It's designed to run really, really like light. And I wanted to wrap it with my SQL SQL Sync sort of core library code. And then I wanted to make sure that I could run that in the browser, in edge workers, absolutely anywhere, in any Wasm runtime basically. So, Inscripten was too heavy for my needs. I needed something lighter weight. So the next thing I did is I looked at Wasm and the component model and all this really awesome stuff that we've been talking about this week. And honestly, I think looking back, this is about two months ago, one and a half months ago that I looked at this, looking back knowing all the stuff I now know about Wasm and also about SQLite, I think I would be able to get this working. But at the time, I was moving very, very fast and what I discovered was that it's much quicker to just use Wasm32 unknown unknown. And so that's what I did. And luckily for me, someone named Treven on the internet released this random patch I found, like literally in some side branch of RU SQLite on in 2022, where he went and did all of the ground work to get SQLite running perfectly in Wasm32 unknown unknown. Now, what does that mean? It means that SQLite is basically compiled without any IO or any access to the outside world. Every single thing that it needs has to be stubbed in. But that's exactly what I wanted because it allowed me to sort of very granularly take control of how SQLite looks at the outside world. And it was a fantastic starting point. So if anyone knows Treven, ow, that hurt. If anyone knows Treven, please let me know and I would love to talk to them because they're amazing person. All right, next slide. So we have SQLite compiled to Wasm. Fantastic, that's a great starting point. Now what we have to do is we have to wrap it because SQLsync has all of that functionality we talked about in the architecture. We have this complex replication architecture. We have to keep around mutations in like a journal, like a timeline. We have to be able to efficiently bring changes to a SQLite database from the server side back down to the client and rebase. We want to be able to do all this very efficiently. We want to be able to test everything. And so I decided to build like what I call the SQLsync core. And SQLsync core is all of that functionality wrapped in a Wasm-friendly Rust library. And it's important to emphasize the Wasm-friendly part of this. And this is I think one of the key things I want to sort of you to take away from this talk is if your goal is to build a Wasm-friendly library, I suggest doing a couple of things. And for people who've done a lot of Wasm stuff this is pretty obvious, but I'm just gonna emphasize them here. The first thing is you want to expose all IOs to the outside world, any kind of interaction with sort of anything as sort of make it pluggable. But even more importantly in Rust is ideally you do this through like pluggable traits and ideally you do this through static compilation. You don't want to end up with a system where you have like a bunch of dynamic pointers everywhere and everything is sort of using like runtime reflection. You don't want that because you're gonna end up paying a huge performance penalty in the relatively constrained runtime environment of Wasm. And so you want to use generics, you want to use traits, you want to be able to make it very sort of like you end up with a version of the SQLsync core that is specifically suited for the particular sets of IO requirements that you need for where you're running SQLsync and for whatever Rust library you're building. So that's the first thing I did. The second thing I did is synchronous versus async is a sort of interesting choice. Like in Rust it's really nice and friendly and then tempting to use async. It gives you a lot of nice ergonomics but it tends to sort of pollute your code. Like if you start using async in one place you will very quickly find out you have to use it sort of everywhere. And it's very difficult to build an async sync boundary. SQLite is a synchronous database. It expects things like the read syscall to just execute and return. There is no concept of asynchronicity. And so if you want to add an async layer, IO layer to SQLite you have to sort of build this bridge. And that adds not only complexity to your code but also adds a performance impact. And remember we're targeting very lightweight environments. We wanna run inside the phone, inside a shared like web worker and we want it to be as fast as possible. So we wanna try to minimize any opportunities to have performance boundaries. So that was the second thing I decided was make everything completely synchronous. And then third thing was assume that you're running in a single thread. This isn't gonna be true forever. Obviously wasm is gonna have threads and really cool like multi-core stuff. But at least for now it simplifies things. And again if you are using, if you're running single thread code you can often find ways to increase performance. Performance is just easier in a single thread context. If you don't have to think about parallelism and multiple things mutating data at the same time. All right, so cool. We have SQL sync core. We have SQLite and wasm. We have all the pieces. So we just put it in the browser, right? Like done. And the funny thing about this is I expected this to be like way harder but it actually just worked. These two projects are amazing. If you have not had the opportunity to work with these projects, I highly recommend it. Both wasm pack and wasm bind gen have just completely shaved months of development time off of SQL sync, like building SQL sync. And I really love them. Now obviously we will eventually have a sort of variant of these projects that are designed in the component model that allow you to take like a wasm component and sort of compile it natively to like the JS stack with componentized JS and all this cool stuff. And I think that's where we're gonna go. But in the meantime, these two projects are world-class and SQL sync core actually bind directly to browser APIs in the browser side of SQL sync core. And I'm able to use pretty much everything as if I was just writing JavaScript with a relatively small performance overhead. So highly recommended both of these projects. All right. And now for maybe the most exciting thing that I did and maybe the most interesting thing about SQL sync. You remember how I talked about like running mutations? So I sort of hand-waved over this. We have like this mutation like new to do and we want to execute it optimistically on the client and then we eventually wanna execute it on the server. And SQLite unfortunately doesn't have like a nice command called new to do. Like there needs to be some kind of translation going on. So imagine that we have this like action create to do give talk at wasm con. This is our mutation, the representation of user intent. We wanna turn that into essentially an insert query, something like this. So we need something in the middle, something that translates from this like data, this user intent to a one or more insert queries or potentially other types of SQL operations that are actually going to apply that intent to a SQLite database. And this is a really, really critical piece of infrastructure. So what are the requirements of this reducer? We not user provided logic. We want sandboxable. We want multi language support. Wanted to be able to embed it. It needs to sit inside of SQL Sync course. It's a really great experience. Can anyone shout out just anything that comes to mind that might help me with this problem? First thing that comes to your mind. Oh, web assembly. Yeah, like why not? I mean, that seems pretty good. It seems like it satisfies all of our requirements. So like let's use that. So yeah, no problem. We have SQL Sync running in wasm and we have the reducer is wasm. We want to make it really nice and ergonomic so like the user can pass the reducer to SQL Sync when it boots up SQL Sync and everything works. This is going to be interesting. So I'd like to say that I use the component model to dynamically leak SQL Sync in the reducer to user code and make it all super, super nice. And you know what? After being here this week and seeing Luke's talk and hearing from all of you all the amazing things happening in the web assembly space I'm now convinced that this will happen. But unfortunately it's not today. So what did I do instead? Well, I put wasm in wasm. Yeah, this is what we did. So running wasm and wasm in Rust, you have a lot of runtimes to choose from. So the first question is like which runtime are we gonna use? I'd love to say I just rolled my own runtime. I did not. I played around with a bunch of runtimes to see if I could convince them to compile to wasm. And for various reasons, the first runtime that I found that was very compelling was wasm. And I noticed this on the docs. And I was like, great, done, sold. I found a wasm runtime. And I mean, wasm, many of you probably know of it. And not only does it work inside wasm, but it's one of its core goals and features to run within wasm efficiently. And it does a really good job. Like I'm honestly very impressed by how fast wasm is. So yeah, that was our goal. So we wanna use wasm. Now, as you all know in this group, communication is hard. Wasm doesn't give you the nice component model. It doesn't give you the canonical ABI interface types, like any of the amazing stuff that you want to have a good experience. So what am I gonna do? Like I need my reducer experience for the user to be nice. I don't want them to have to roll their own sort of like memory manipulation and stuff like that. So I need some kind of like re-entrant API with support structure types. And so I really am excited that I could do this. This is the SQL Sync reducer spec in one slide. This is everything you need to build. Like if you just had this slide, you could build a valid SQL Sync reducer as long as your wasm module exports those six functions on the left side and works with this sort of like host-based API, you can build a reducer. So I'll just call it like a couple of key things. The first four methods that are exported on the left side are basically initialization and memory management, right? So super simple, you're gonna see this in almost every single ABI between wasm and some host. And then the last two functions are specific for the reducer sort of workflow. Because if you see on the right side where we have this reduce function, we have to enter wasm the first time, which is basically FFI reduce, which basically says, okay, we're gonna work on this mutation. But then wasm is going to basically want to run some queries. And so the way that I built this is like a reactor style model. So wasm returns to you a bunch of requests, like I wanna run these queries, the server runs those queries or the SQL Sync runs those queries, writes the results directly into wasm memory and then basically just round trips back to wasm. And so we have this little reactor core that can make progress. And on the user side, so I wanna run a reducer, I wanna write a reducer, this is the user experience. I wrote like a really simple Rust library that just wraps this reducer function that the user exports. And one thing you'll notice that's interesting is that this is a fully async library. And how did I do that? Well, I wrote a executor, like a regular Rust futures executor, which then works with that Rust, that ABI that I just defined to basically translate, you know, awaits into essentially buffering up requests, sending it to the other side of the host. So essentially what I've done is I've built a full Rust future executor, which then forwards all of the actual, like it yields work to the actual host through the law of the boundary. And so this ends up with, I think, a very nice user experience. You can run queries, you can use all of the regular, like async wait syntax from Rust, and you can build a reducer. So this is the reducer concept, cool. And that gets us to hopefully the good part of the talk. I hope everyone followed along. I know I moved pretty quickly, but my goal ultimately was to get to this point, which is basically demoing what I built. And that's what I'm really excited about. And we all like live demos and please, please live demo work. So without further ado, first of all, I'm going to switch to my phone because I trust my phone much better than I trust anyone else. Okay, cool. Mr. Phone, please stay alive. On the left side of our screen, I'm going to open up this little program that I wrote. As I probably hinted at, I really like to-do lists. I think we all need to-do lists in our lives. And so SQL Sync, I wrap SQL Sync with like a little to-do list application. So I just want to emphasize that this is a very simple application. You could build quite more complex and interesting things, but I think this demonstrates the core functionality of SQL Sync. So on the left side, we have like a normal to-do list, like a finish wasm con talk. Pretty normal. Nothing's super exciting here. However, if I open this to-do list in Safari on the right side of the screen, we notice something interesting. We notice that it's now synchronized. Now how is that synchronized happening? What's happening is that whole replication stack that I talked about earlier is running. And where is the coordinator server running? Well, it's running through my phone to Cloudflare Durable Objects. And somewhere inside of the Cloudflare Durable Objects stack, they're running a little piece of code, which is running my full SQL Sync core wasm stack with SQL Sync running with all of this really cool stuff. And that's what's handling this replication between these two to-do lists. And then I can add something. And as you can see, it's pretty quick. That entire round trip was probably in the order of one or two milliseconds. And that includes essentially running mutation optimistically. So we see the result on the right side instantaneously. And then essentially doing that whole rebase loop with server. Cool. Now, as I said, offline first apps are the cool apps, right? So let's go ahead and make these offline. So now there's no server changes. If I delete stuff, it's all good. If I add stuff, like this is Chrome. Well, it's actually Arc, but whatever. This is Safari. As we can see, we're changing the state of the system. We now have diverged databases, right? So the critical thing, and the thing that we've been talking about this whole time is offline first apps have to be able to re-converge their state. And as you can see, as soon as they both became online, we get to the exact same state. And this is a very amazing experience. Like, this is the experience that you want in your application. And so that's the experience that SQL Sync provides with relatively simple things. But there's more. Let me go ahead and open up another Safari window. Ah, let me do this. Hello? No, demo gods. Internet, please do the thing, do the thing you're supposed to do. Okay, cool, apparently new tab is faster than new window. Don't ask me questions. Okay, so let's just go ahead and simplify the state here. And in addition, I'm gonna demo one more feature, which is real-time SQL queries. So on the left side, we're gonna, well, whatever. We'll get to that in a second. First of all, on the right side, we have two Safari tabs. They are linked. Now, they're both disconnected from the internet, but they're still synchronized. And the reason that they're synchronized is because I use shared workers. And so the entire T of SQL Sync is running in a shared worker and is automatically keeping these two tabs in sync. Now, how does this actually work? How do the queries work? So it can come back online. When it comes back online, we're gonna see that test on the left side. On the left side, you're also gonna see another interesting feature, which is the query viewer. So SQL Sync has a fully reactive query execution engine. So as the data changes under the hood, we see that this query output, the select star from tasks change. And even cooler, I could just be like, where description like SQL Sync? And doing this isn't too hard running inside of one browser. But what if I add SQL Sync over here and see that query get updated across the internet? I think that's pretty cool. So that's SQL Sync. That's what I've built. Obviously, this is a pretty trivial demo, but what makes this a little bit of a crazy idea is honestly I'd love to just see what happens. Is anyone interested in trying this out for yourselves? If you wanna do hard mode, you go on the right side, which is a multiplayer, which means that you'll all be in the same to-do list document. And this has never been tested before ever. And on the left side, you get your own little to-do list that you can happily manipulate yourself. So I'll give everyone a moment to just open it up and then I'm gonna switch over to it and see what it looks like with everyone playing around. Just checking that I haven't completely screwed this up. Does anyone have it running on their thing? You should see. Yeah, you do. Okay, we have at least one person. We're gonna go to the multiplayer. Oh, wow, that's a lot. Someone do something. Oh, my God, it's live. Holy crap, it works. Okay, well, cool. That was the first time that ever happened. So this is real-time SQL Sync. All right, while you guys play around with that, feel free to use the single-player mode to have your own to-do list. It's fully durable and it's replicated internationally and cross-device. Let's just really quickly recap. What did we learn today? So the first thing is that we compiled SQLite to Wasm. Luckily we got to stand on the shoulders of giants and that experience was not as painful as it probably could have been. It's gonna get a lot better as a component model evolves and we'll be able to build a much more sort of clean Wasm SQLite abstraction. But for now, we get it, great. The second thing is we built this core Rust library that allowed us to really easily run within many different run times in many different Wasm environments. This is critical because I want SQL Sync to run inside of your browser, inside your phone, inside your mobile apps. Wherever you can run Wasm, I want SQL Sync to work, which means I need to be able to bind to different storage engines. I need to be able to bind to different ways of doing things and that's really important. The third thing is I added this web worker layer and Cloudflare durable objects layer. I didn't really talk too much about that because of time but as you can see from the working demo, those things do exist and I think it's pretty cool. It's a good example of how powerful Wasm is that you could run it in the browser and on the edge. And then finally I did Wasm and Wasm which I never thought I would actually do in like a real thing but I'm honestly pretty happy. It just sort of works. Kudos to the Wasm you guys. So yeah, and what do you get? Magical collaborative SQLite. I think that's pretty happy. I'm pretty happy with a couple of months of work to get there. But there's one critical step missing. This is a step that I need all of your helpless. You see I need to make a really hard decision. I need to make it right this second. If anyone is interested in me clicking the button on the right, please cheer. Give me something. All right folks, we're doing it live. This is the SQL Sync GitHub repo. Orbiting Hail SQL Sync. And this is the change visibility, the red button. And this is the thing. I haven't actually tested this yet so I don't know all the steps. What is it? Okay, yes, I understand. I have to type something for it. Oh, I have to do it. All right, remember, first star gets a prize, right? It's Orbiting Hail Slash SQL Sync. Here we go, folks. Oh, I have to do this. It's like, no one, no one look at the thing. Oh no, I have so many security layers on my computer. So many layers. Okay, I think it's live. Yeah, it's live. We did it. So yeah, that's the talk, folks. SQL Sync. If you liked this, if you thought it was cool, if you want to see more weird database experiments, please consider giving it a GitHub star. I would really appreciate it. Over the coming months, I will be working on this full time and really trying to see if I have something here that's worth building a company around. But in the meantime, it is open source and please enjoy. Thank you so much. And I did blast through that talk so we have a little bit of time. If anyone has any questions. Tyler. Yeah, it's the hardest part. So in the offline first phase, or first the question, the question was really about when you have essentially, you have to deal with conflict somehow. Like when you have updates coming in from multiple clients, how do you actually converge that state? And that's a really hard problem. So a lot of the offline first community has done a lot of research into things called CRDTs, conflict-free replicated data types, which allow for convergence as long as all events eventually arrive. They don't care about the order in which the events, they guarantee sort of like a final state. Now those data models are really great for like sort of property-bag style models where you end up with like a lot of like, you want to converge like a dictionary of key values, for example. Super, super great. But when you're talking about the entire complexity of SQL lights relational data model, it's really hard to fit the CRDT system into that. Like it doesn't naturally align. So I went a very different approach with SQL sync. Basically I said, well, locally when we run a mutation, we can optimistically apply it safely because we have a static state, we can look at the state and we can run the mutation locally. When we go remote, we want to guarantee one thing, which is essentially a global order of all the mutations. So the remote side runs mutations completely sterilized. There's one mutation at a time. This is very important. The next thing is that we need a way for the mutation to actually execute logic because we need it to be able to handle conflicts itself. And so that's why the reducer isn't just a SQL execution engine. It is actually a full piece of wasm code where you can run arbitrary code. So in some of my other experiments of SQL sync that I didn't demo today because they're a little bit more complex to reason about, in the reducer, the reducer doesn't just say, take a piece of data and run an update query. The reducer actually runs select queries to observe the state of the database at the time at which the mutation runs. And critically, because we have a rebase architecture, when the mutation runs on the client, it might affect the state in one way. And when the mutation eventually runs on the server, it might see a different state and affect the state in a different way. And by doing this, we allow the user, the developer, to opt into the specific types of sort of conflict detection and conflict resolution that they want. Now out of the box, if you actually just use update queries with like on-dupe key update on like key value style approach to SQLite, you basically just automatically get last write wins consistency, which is a great starting point. But at some point you're gonna want to encode some kind of more complex consistency in your app. Like let's say you had a to-do list, you wanted to support sorting the to-do list manually by a user, so like drag and drop. This is a little bit harder to build. But the nice thing about SQL sync it allows you to encode that sort of like relationships between a mutation and like the state of the system into the mutation itself. And then you can apply logic at execution time. Long story short, the solution is not solved, but SQL sync gives you a very nice, very easy to reason about system to solve it in. And then when you combine it with SQLite, which is actually fantastic. It has so many tools to deal with duplicates and conflicts. It is not as hard as it should be. So long story short, it sort of works. And I'm excited for people to play with it and feel how it works. Any other questions? Great, great question. So the question is essentially, in a lot of applications we don't want just like, we want sort of one database. Like we want like a meta database that contains all the state. Or we want like a bunch of small databases with like shards state. It's essentially like depending on the database or the application, it's not necessarily true that for example in the to-do list case, you just want like one big to-do list for all of your users. So in the to-do list case, I think it's a good example to start with. When you guys, if you guys use that sort of second, that you are on the left, essentially what's happening is that every single person who hits that QR code gets their own SQLite database. It's a completely independent document model. And so that's the target that I'm going with for SQL Sync. SQL Sync is not good at storing all the data of your company. That's not the end goal of SQL Sync. If you think about the types of apps that I'm talking about at the very beginning of the talk, Google Docs, Figma, these types of applications, they have what I call as like the document model. You go into Figma, you don't load all of the state for all of the Figma documents when you open Figma. But you do load all of the state of a single Figma document when you load a document, like when you open a Figma file. And that's the model that I'm going with first. So SQL Sync is highly optimized towards essentially small, like using SQLite as essentially a collaborative file format. And it should be, it's sharded automatically at like a higher level. So essentially you would still use SQL Sync along with your like normal backend database to be able to do authentication and all this type of stuff. And essentially outsource the collaborative part of your app to SQL Sync, but keeping like the high level metadata of which documents exist and the state of those documents in your like higher level, normal centralized backend. Not necessarily per user, but you have per document multi-tenancy, yeah. So essentially every document is essentially its own thing. And even in the Cloudflare Durable objects side of it, every single document is a individual Cloudflare Durable object in this current instance of the SQL Sync backend. Which means that like when you all were scanning this, anyone who's using the single player was actually running on a completely distinct server from everyone using multiplayer. And that means that the scene automatically scales. I don't have to worry about the ops side of this. The server is very, very simple. So yeah, great questions. Any other questions? Cool. Well, it is lunchtime and I really appreciate all of your time. Definitely star us on GitHub or star me on GitHub or single sync on GitHub. And I'd love to hear any feedback after the talk. I'll be at lunch, come find me.