natto's approach to local-first

It's too familiar an experience when a web service shuts down and you lose access to the software, not to mention your work and data. At the same time, web apps have really improved and multiplayer collaboration has become table stakes. Is it possible to have today's expected SaaS experience as well as software that lasts?

If you're interested in this problem, I recommend reading this Ink & Switch article on Local-first software. The article presents seven principles which I use to evaluate my approach with natto.dev.

natto has these goals

  • A cloud sync experience that you expect. Your data syncs across multiple devices and is accessible wherever you have internet.
  • If (when?) natto shuts down, you can continue to use natto.
  • You're able to use natto without an account. This isn't a primary goal but is necessary to support the shut down use case.

Approach

natto has a two-mode approach. You can either use natto with a synced user canvas or a local canvas. You choose the mode when you create a canvas.

Synced user canvas

To use a user canvas, you need to log in to your natto account. Any changes you make are synced to natto's server and are reflected live on other devices. Each user canvas has a unique URL you can share with others. This is your traditional SaaS experience. Behind the scenes, natto uses an OT-like mechanism so the webapp is responsive even if your internet connection is slow or disconnects.

Local canvas

You can save and open canvases to .natto files. This flow works without an account. Additionally in Chrome, natto will automatically save changes to the file.

Transition between modes

You can save a user canvas to a local file. And you can create a user canvas from any canvas (if logged in).

Scorecard

Let's look at the seven requirements from the Ink & Switch article. Depending on how you evaluate natto, you'll end up with one of the following score cards.

notion image
 
notion image

Fast

I consider both synced user canvases and local canvases "fast". Any operations are processed immediately on the client, even for synced canvases. Synced canvases are not stored on the client, however, so the initial load requires waiting for the server.

Multi-device

Synced canvases are accessible from multiple browser with internet. Local canvases are saved to files, which is portable to other devices. You have to manage this yourself though (eg Dropbox, git, email).

Offline

I plan to bundle up natto as a PWA/beloved electron app, which would allow you to use natto offline with local canvases. However, synced canvases cannot be loaded offline.

Longevity

.natto files are just JSON. I plan to make a downloadable thing that should work as long as it installs. Even if the schema changes, you should be able to download a version of the software that works for your file. Synced canvases fail the longevity criteria.

Privacy

Same story as offline and longevity. Local canvases don't leave your computer. Synced canvases do.

User control

Again, .natto files are just JSON. You're also able to save synced canvases to file. Having a JSON file creates a free API - you can edit the JSON in your own tool and reopen it in natto. You can even create your own client and backend.

Tradeoffs

This sounds pretty good! What gives?

I think the main tradeoff is user experience. When creating a canvas, you have to choose between two types of canvases. Should they create an account and log in? The two-mode complexity is exposed to the user.

You can save a synced canvas to a local file but you can't merge that file back to the original synced canvas. This is where CRDTs can come into play, although that would introduce complexity elsewhere. For example, the saved files would need to encode more than the current state.

Not locking users to the SaaS offering is a business risk. How are you going to collect that recurring revenue?

Future

I hope one day we find the holy-grail solution - an approach that satisfies all the principles laid above. CRDTs are promising but still need work. The Braid Protocol extends transfer protocols to support distributed syncing. There's lot of exciting activity in this space!

Until then, I'm pretty happy with natto's choose-your-adventure approach.

I'd love to hear your thoughts on this problem! Do you know software that handles this well?

 
November 8, 2021
Browse more posts or follow on Twitter.