<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: ben-johnson</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/ben-johnson.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2025-10-03T15:10:21+00:00</updated><author><name>Simon Willison</name></author><entry><title>Litestream v0.5.0 is Here</title><link href="https://simonwillison.net/2025/Oct/3/litestream/#atom-tag" rel="alternate"/><published>2025-10-03T15:10:21+00:00</published><updated>2025-10-03T15:10:21+00:00</updated><id>https://simonwillison.net/2025/Oct/3/litestream/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://fly.io/blog/litestream-v050-is-here/"&gt;Litestream v0.5.0 is Here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I've been running &lt;a href="https://litestream.io"&gt;Litestream&lt;/a&gt; to backup SQLite databases in production for a couple of years now without incident. The new version has been a long time coming - Ben Johnson took &lt;a href="https://simonwillison.net/2022/Sep/21/introducing-litefs/"&gt;a detour&lt;/a&gt; into the FUSE-based &lt;a href="https://github.com/superfly/litefs"&gt;LiteFS&lt;/a&gt; before deciding that the single binary Litestream approach is more popular - and Litestream 0.5 just landed with this very detailed blog posts describing the improved architecture.&lt;/p&gt;
&lt;p&gt;SQLite stores data in pages - 4096 (by default) byte blocks of data. Litestream replicates modified pages to a backup location - usually object storage like S3.&lt;/p&gt;
&lt;p&gt;Most SQLite tables have an auto-incrementing primary key, which is used to decide which page the row's data should be stored in. This means sequential inserts to a small table are sent to the same page, which caused previous Litestream to replicate many slightly different copies of that page block in succession.&lt;/p&gt;
&lt;p&gt;The new LTX format - borrowed from LiteFS - addresses that by adding compaction, which Ben describes as follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We can use LTX compaction to compress a bunch of LTX files into a single file with no duplicated pages. And Litestream now uses this capability to create a hierarchy of compactions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;at Level 1, we compact all the changes in a 30-second time window&lt;/li&gt;
&lt;li&gt;at Level 2, all the Level 1 files in a 5-minute window&lt;/li&gt;
&lt;li&gt;at Level 3, all the Level 2’s over an hour.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Net result: we can restore a SQLite database to any point in time, &lt;em&gt;using only a dozen or so files on average&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'm most looking forward to trying out the feature that isn't quite landed yet: read-replicas, implemented using a SQLite &lt;a href="https://www.sqlite.org/vfs.html"&gt;VFS extension&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The next major feature we’re building out is a Litestream VFS for read replicas. This will let you instantly spin up a copy of the database and immediately read pages from S3 while the rest of the database is hydrating in the background.&lt;/p&gt;
&lt;/blockquote&gt;

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=45453936"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/fly"&gt;fly&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/litestream"&gt;litestream&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ben-johnson"&gt;ben-johnson&lt;/a&gt;&lt;/p&gt;



</summary><category term="sqlite"/><category term="fly"/><category term="litestream"/><category term="ben-johnson"/></entry><entry><title>Quoting Ben Johnson</title><link href="https://simonwillison.net/2023/Jan/26/ben-johnson/#atom-tag" rel="alternate"/><published>2023-01-26T19:36:03+00:00</published><updated>2023-01-26T19:36:03+00:00</updated><id>https://simonwillison.net/2023/Jan/26/ben-johnson/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://mastodon.xyz/@benbjohnson/109757173611956937"&gt;&lt;p&gt;[On SQLite for production concurrent writes] In general, WAL mode “just works” as Simon said. You just need to make sure you don’t have long running write transactions, although those are somewhat problematic in any database system. Don’t do stuff like starting a write txn and then calling a remote API and then committing. That’ll kill your write throughout.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://mastodon.xyz/@benbjohnson/109757173611956937"&gt;Ben Johnson&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ben-johnson"&gt;ben-johnson&lt;/a&gt;&lt;/p&gt;



</summary><category term="sqlite"/><category term="ben-johnson"/></entry><entry><title>Introducing LiteFS</title><link href="https://simonwillison.net/2022/Sep/21/introducing-litefs/#atom-tag" rel="alternate"/><published>2022-09-21T18:56:42+00:00</published><updated>2022-09-21T18:56:42+00:00</updated><id>https://simonwillison.net/2022/Sep/21/introducing-litefs/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://fly.io/blog/introducing-litefs/"&gt;Introducing LiteFS&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
LiteFS is the new SQLite replication solution from Fly, now ready for beta testing. It’s from the same author as Litestream but has a very different architecture; LiteFS works by implementing a custom FUSE filesystem which spies on SQLite transactions being written to the journal file and forwards them on to other nodes in the cluster, providing full read-replication. The signature Litestream feature of streaming a backup to S3 should be coming within the next few months.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=32925734"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/databases"&gt;databases&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/replication"&gt;replication&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/fly"&gt;fly&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/litestream"&gt;litestream&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ben-johnson"&gt;ben-johnson&lt;/a&gt;&lt;/p&gt;



</summary><category term="databases"/><category term="replication"/><category term="sqlite"/><category term="fly"/><category term="litestream"/><category term="ben-johnson"/></entry><entry><title>How the SQLite Virtual Machine Works</title><link href="https://simonwillison.net/2022/Sep/7/how-the-sqlite-virtual-machine-works/#atom-tag" rel="alternate"/><published>2022-09-07T20:49:10+00:00</published><updated>2022-09-07T20:49:10+00:00</updated><id>https://simonwillison.net/2022/Sep/7/how-the-sqlite-virtual-machine-works/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://fly.io/blog/sqlite-virtual-machine/"&gt;How the SQLite Virtual Machine Works&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
The latest entry in Ben Johnson’s series about SQLite internals.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/databases"&gt;databases&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ben-johnson"&gt;ben-johnson&lt;/a&gt;&lt;/p&gt;



</summary><category term="databases"/><category term="sqlite"/><category term="ben-johnson"/></entry><entry><title>How SQLite Scales Read Concurrency</title><link href="https://simonwillison.net/2022/Aug/24/how-sqlite-scales-read-concurrency/#atom-tag" rel="alternate"/><published>2022-08-24T16:16:19+00:00</published><updated>2022-08-24T16:16:19+00:00</updated><id>https://simonwillison.net/2022/Aug/24/how-sqlite-scales-read-concurrency/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://fly.io/blog/sqlite-internals-wal/"&gt;How SQLite Scales Read Concurrency&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Ben Johnson’s series on SQLite internals continues—this time with a detailed explanation of how the SQLite WAL (Write-Ahead Log) is implemented.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=32579866"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/databases"&gt;databases&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ben-johnson"&gt;ben-johnson&lt;/a&gt;&lt;/p&gt;



</summary><category term="databases"/><category term="sqlite"/><category term="ben-johnson"/></entry><entry><title>How SQLite Helps You Do ACID</title><link href="https://simonwillison.net/2022/Aug/10/sqlite-rollback-journal/#atom-tag" rel="alternate"/><published>2022-08-10T15:39:09+00:00</published><updated>2022-08-10T15:39:09+00:00</updated><id>https://simonwillison.net/2022/Aug/10/sqlite-rollback-journal/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://fly.io/blog/sqlite-internals-rollback-journal/"&gt;How SQLite Helps You Do ACID&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Ben Johnson’s series of posts explaining the internals of SQLite continues with a deep look at how the rollback journal works. I’m learning SO much from this series.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/benbjohnson/status/1557377929583026181"&gt;@benbjohnson&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/fly"&gt;fly&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ben-johnson"&gt;ben-johnson&lt;/a&gt;&lt;/p&gt;



</summary><category term="sqlite"/><category term="fly"/><category term="ben-johnson"/></entry><entry><title>SQLite Internals: Pages &amp; B-trees</title><link href="https://simonwillison.net/2022/Jul/27/sqlite-internals-pages-b-trees/#atom-tag" rel="alternate"/><published>2022-07-27T14:57:25+00:00</published><updated>2022-07-27T14:57:25+00:00</updated><id>https://simonwillison.net/2022/Jul/27/sqlite-internals-pages-b-trees/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://fly.io/blog/sqlite-internals-btree/"&gt;SQLite Internals: Pages &amp;amp; B-trees&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Ben Johnson provides a delightfully clear introduction to SQLite internals, describing the binary format used to store rows on disk and how SQLite uses 4KB pages for both row storage and for the b-trees used to look up records.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/benbjohnson/status/1552290457484288000"&gt;@benbjohnson&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/algorithms"&gt;algorithms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/databases"&gt;databases&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ben-johnson"&gt;ben-johnson&lt;/a&gt;&lt;/p&gt;



</summary><category term="algorithms"/><category term="databases"/><category term="sqlite"/><category term="ben-johnson"/></entry><entry><title>SQLite Happy Hour - a Twitter Spaces conversation about three interesting projects building on SQLite</title><link href="https://simonwillison.net/2022/Mar/23/sqlite-happy-hour/#atom-tag" rel="alternate"/><published>2022-03-23T22:01:07+00:00</published><updated>2022-03-23T22:01:07+00:00</updated><id>https://simonwillison.net/2022/Mar/23/sqlite-happy-hour/#atom-tag</id><summary type="html">
    &lt;p&gt;Yesterday I hosted SQLite Happy Hour. my first conversation using Twitter Spaces. The idea was to dig into three different projects that were doing interesting things on top of SQLite. I think it worked pretty well, and I'm curious to explore this format more in the future.&lt;/p&gt;
&lt;p&gt;Here's &lt;a href="https://twitter.com/simonw/status/1504604448202518529"&gt;the tweet&lt;/a&gt; that initially promoted the space:&lt;/p&gt;

&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;Interested in devious tricks to push the envelope of what you can do with SQLite?&lt;br /&gt;&lt;br /&gt;Join myself, &lt;a href="https://twitter.com/benbjohnson?ref_src=twsrc%5Etfw"&gt;@benbjohnson&lt;/a&gt;, &lt;a href="https://twitter.com/geoffreylitt?ref_src=twsrc%5Etfw"&gt;@geoffreylitt&lt;/a&gt; and &lt;a href="https://twitter.com/nschiefer?ref_src=twsrc%5Etfw"&gt;@nschiefer&lt;/a&gt; on Tuesday for a Twitter Spaces conversation about &lt;a href="https://twitter.com/litestream?ref_src=twsrc%5Etfw"&gt;@litestream&lt;/a&gt;, &lt;a href="https://twitter.com/datasetteproj?ref_src=twsrc%5Etfw"&gt;@datasetteproj&lt;/a&gt; and Riffle!&lt;a href="https://t.co/ukRMVgC09u"&gt;https://t.co/ukRMVgC09u&lt;/a&gt;&lt;/p&gt;- Simon Willison (@simonw) &lt;a href="https://twitter.com/simonw/status/1504604448202518529?ref_src=twsrc%5Etfw"&gt;March 17, 2022&lt;/a&gt;&lt;/blockquote&gt;

&lt;p&gt;My co-hosts, representing the three projects, were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ben Johnson &lt;a href="https://twitter.com/benbjohnson"&gt;@benbjohnson&lt;/a&gt;, creator of &lt;a href="https://litestream.io/"&gt;Litestream&lt;/a&gt; - a tool that adds replication to SQLite built on top of the WAL mechanism.&lt;/li&gt;
&lt;li&gt;Geoffrey Litt &lt;a href="https://twitter.com/geoffreylitt"&gt;@hgeoffreylitt&lt;/a&gt; and Nicholas Schiefer &lt;a href="https://twitter.com/nschiefer"&gt;@nschiefer&lt;/a&gt; who are working on Riffle, a project exploring the idea of driving reactive user interfaces using SQL queries - see &lt;a href="https://riffle.systems/essays/prelude/"&gt;Building data-centric apps with a reactive relational database&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Twitter Spaces recorded audio only lasts for 30 days, so I've exported the audio and shared it &lt;a href="https://soundcloud.com/simon-willison/sqlite-happy-hour-22nd-march-2022"&gt;on SoundCloud&lt;/a&gt; as well.&lt;/p&gt;

&lt;iframe width="100%" height="166" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/1237563277&amp;amp;color=%23ff5500&amp;amp;auto_play=false&amp;amp;hide_related=false&amp;amp;show_comments=true&amp;amp;show_user=true&amp;amp;show_reposts=false&amp;amp;show_teaser=true"&gt; &lt;/iframe&gt;&lt;div style="font-size: 10px; color: #cccccc;line-break: anywhere;word-break: normal;overflow: hidden;white-space: nowrap;text-overflow: ellipsis; font-family: Interstate,Lucida Grande,Lucida Sans Unicode,Lucida Sans,Garuda,Verdana,Tahoma,sans-serif;font-weight: 100;"&gt;&lt;a href="https://soundcloud.com/simon-willison" title="Simon Willison" target="_blank" style="color: #cccccc; text-decoration: none;"&gt;Simon Willison&lt;/a&gt; · &lt;a href="https://soundcloud.com/simon-willison/sqlite-happy-hour-22nd-march-2022" title="SQLite Happy Hour - 22nd March 2022" target="_blank" style="color: #cccccc; text-decoration: none;"&gt;SQLite Happy Hour - 22nd March 2022&lt;/a&gt;&lt;/div&gt;

&lt;h4&gt;Collaborative notes from the session&lt;/h4&gt;
&lt;p&gt;Something I've observed in Twitter Spaces I've joined in the past is that they can really benefit from a dedicated back-channel, to share links and allow audience participation without people needing to first request to speak.&lt;/p&gt;
&lt;p&gt;A trick I've used with online talks I've given in the past is to start a collaborative Google Doc to collect shared notes and questions. I tried this for the Twitter Space, and it worked really well!&lt;/p&gt;
&lt;p&gt;You &lt;a href="https://docs.google.com/document/d/1ykZdd-Q_PF21N239T7EolOFSM-dHJUjjM2NVP5K26oQ/edit#"&gt;see that document here&lt;/a&gt;. During the session the document was open for anyone to edit - I've locked it down now that the session has ended.&lt;/p&gt;
&lt;p&gt;I've duplicated the final form of the document at the bottom of this post.&lt;/p&gt;
&lt;p&gt;Something I really like about this format is that it allows for additional material to be posted later. I spent some time adding more detailed answers to the questions about Datasette after the session had ended.&lt;/p&gt;
&lt;h4&gt;Thoughts for if I do this again&lt;/h4&gt;
&lt;p&gt;This was my first time hosting a space, and I learned a lot along the way.&lt;/p&gt;
&lt;p&gt;Firstly, this kind of thing works the best when there is a back and forth between the participants.&lt;/p&gt;
&lt;p&gt;My original idea was to have each project talk for ten minutes, then spend five minutes on discussion between the panel before moving on to the next project - and 15 minutes of open discussion at the end.&lt;/p&gt;
&lt;p&gt;My co-hosts suggested we try to make it more conversational, interrupting each other as we went along. We did that, and it worked much better: these conversations are far more interesting as a conversation than a monolog.&lt;/p&gt;
&lt;p&gt;I still don't have a great feel for when to interrupt people in an audio-only conversation, since unlike an in-person panel there are no visual clues to go off!&lt;/p&gt;
&lt;p&gt;Techology: it turns out Twitter Spaces has wildly different functionality on web v.s. mobile apps. We spent the first five minutes making sure all of our speakers could talk! We really should have done a tech rehearsal first, but I wasn't sure how to do that without accidentally broadcasting it to the world - maybe setup burner Twitter accounts for testing?&lt;/p&gt;
&lt;p&gt;Presenting audio-only is itself a challenge: I'm used to leaning on visual demos when I explain what Datasette is in a talk, and not having those to fall back on was challenging. I had jotted down notes on the main points I wanted to hit which certainly helped, but I think there's a whole new presenting skill here that I need to work harder to develop.&lt;/p&gt;
&lt;p&gt;Exporting the recorded audio from Twitter was frustrating but possible. I wrote some notes on how I did that &lt;a href="https://til.simonwillison.net/twitter/export-edit-twitter-spaces"&gt;in this TIL&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Our collaborative notes in full&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;SQLite Happy Hour Twitter Space&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;22nd March 2022 - &lt;a href="https://www.worldtimebuddy.com/?qm=1&amp;amp;lid=5128581,5391959,5419384,2643743&amp;amp;h=5128581&amp;amp;date=2022-3-22&amp;amp;sln=15.5-16.5&amp;amp;hf=1"&gt;12:30pm PT / 1:30pm MT / 3:30pm ET&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Welcome to the SQLite Happy Hour! This hour-long session will feature three projects that are doing interesting things with SQLite. Each project will provide a ten minute overview, followed by five minutes of discussion from the panel. The last 15 minutes of the hour will be an open discussion and general Q&amp;amp;A.&lt;/p&gt;
&lt;p&gt;This document is open for anyone to edit. Please feel free to drop notes and questions in as we go along.&lt;/p&gt;
&lt;p&gt;The recording of the space is available here: &lt;a href="https://twitter.com/i/spaces/1ypKdEXvkMLGW"&gt;https://twitter.com/i/spaces/1ypKdEXvkMLGW&lt;/a&gt;&lt;/p&gt;
&lt;h5&gt;Riffle&lt;/h5&gt;
&lt;p&gt;Geoffrey Litt &lt;a href="https://twitter.com/geoffreylitt"&gt;@geoffreylitt&lt;/a&gt;, Nicholas Schiefer &lt;a href="https://twitter.com/nschiefer"&gt;@nschiefer&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Riffle asks: what if you wrote your whole UI as a query over a local database? So far, we've built a prototype using SQLite and React. More background in this paper:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://riffle.systems/essays/prelude/"&gt;Building data-centric apps with a reactive relational database&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Research project goal is to make development simpler, as opposed to the ongoing trend of more complexity.&lt;/p&gt;
&lt;p&gt;Riffle looks at having a database-centric mechanism at the heart of the view. Declarative queries could make apps easier to understand and debug.&lt;/p&gt;
&lt;p&gt;SQLite is the tool used for the prototype.&lt;/p&gt;
&lt;p&gt;Local first architecture: Ink &amp;amp; Switch have been promoting this. Return to a world where you local client device serves as a source of truth - you can access data offline etc - and when the network is available your data gets synced to the cloud.&lt;/p&gt;
&lt;p&gt;The prototype: a reactive layer that uses SQLite as a state management backend for React, using &lt;a href="https://sql.js.org/#/"&gt;https://sql.js.org/&lt;/a&gt; which compiles SQLite in WASM. Also built prototypes of desktop apps using &lt;a href="https://github.com/tauri-apps/tauri"&gt;https://github.com/tauri-apps/tauri&lt;/a&gt; - like Electron but using the system web browser instead of bundling its own.&lt;/p&gt;
&lt;p&gt;Since they control the writes, they can re-execute every query after any writes happen. SQLite is so fast that this works fine, queries all take under a ms and even with a thousand queries you can still run them all.&lt;/p&gt;
&lt;p&gt;ALL UI state is in the database - there's no local React component state - literally everything is in the database. This means all UI state is persistent by default.&lt;/p&gt;
&lt;p&gt;IndexedDB is used for the in-browser persistence. The Tauri desktop app stores to a file on disk. Maybe SQL.js could do that with the new Chrome filesystem API stuff too?&lt;/p&gt;
&lt;p&gt;Questions about Riffle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Will Riffle target vanilla JS, or Node.js?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It's running client-side, so vanilla JS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;From Stephen: What about browser-native UI state like scroll position, URL path, query string, multiple independent browser tabs, etc?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Great question. We do some syncing of browser-native state to put it in the DB: eg, to support virtualized list rendering we update scroll state in the DB with an event handler. But there's definitely some browser state that isn't being captured reliably. In the purest world, the pixels on your screen would be produced by a DB query :)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;From Predrag Gruevski: Would "query the queries" be a viable approach for narrowing the set of queries that need to be re-executed after a given write? Simple example: if table X gets modified, query for all queries that have table X in a FROM clause, then re-execute them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;yeah, that's roughly the direction we're headed. It's a little trickier than that if you start having subqueries / materialized view, but good general idea&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;From Longwei Su: Right now, each db update will cause a whole refresh. Is there any plan to refine the binding? So that any db update will only trigger UI component that "subscribe" to this section of the data. Sqlite have trigger, which can have callback on record update. How to construct that  "publisher"-&amp;gt; "subscriber" mapping from sql query?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Comments for Riffle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;From Jesse - &lt;a href="http://web.dev/file-system-access/"&gt;http://web.dev/file-system-access/&lt;/a&gt; isn't a very rich api - I think you could persist to it, but I don't think you can seek/update/.../all the posix stuff sqlite probably needs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hasura &lt;a href="https://github.com/hasura/graphql-engine/blob/master/architecture/live-queries.md"&gt;documented&lt;/a&gt; how they do reactive queries with Postgres, might be useful for minimising refetch overhead?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Datasette&lt;/h5&gt;
&lt;p&gt;Simon Willison &lt;a href="https://twitter.com/simonw"&gt;@simonw&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://datasette.io/"&gt;Datasette&lt;/a&gt; is an open source multi-tool for exploring and publishing data. It explores SQLite as a read-only mechanism for publishing structured data online in as flexible a manner as possible, and aims to build an ecosystem of plugins that can handle a wide range of exploratory data analysis challenges.&lt;/p&gt;
&lt;p&gt;Video introduction here: &lt;a href="https://simonwillison.net/2021/Feb/7/video/"&gt;https://simonwillison.net/2021/Feb/7/video/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Questions about Datasette:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;How does it compares with &lt;a href="https://github.com/dinedal/textql"&gt;https://github.com/dinedal/textql&lt;/a&gt;, it seems the same but instead of sqlite binaries, just raw csv files which are more ubiquitous, and easier to view and edit with with office software (msf excel, libreoffice calc) ?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sqlite-utils memory provides similar functionality: &lt;a href="https://simonwillison.net/2021/Jun/19/sqlite-utils-memory/"&gt;https://simonwillison.net/2021/Jun/19/sqlite-utils-memory/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Does Datasette need to worry about SQLite's &lt;a href="https://www.sqlite.org/security.html"&gt;Defense Against the Dark Arts&lt;/a&gt; security guidelines?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Yes, absolutely! I've put a lot of work in there. Most importantly, Datasette enforces a time limit on queries, which cuts them off if they take more than a second.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The SQLite3 docs are sometimes light on examples for the tricky stuff (e.g., enabling WAL). What's your best sort of info beyond the official docs?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I've been publishing my own notes here: &lt;a href="https://til.simonwillison.net/sqlite"&gt;https://til.simonwillison.net/sqlite&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The SQLite Forum is amazing - I ask questions on there and often get a reply from the maintainers within a few hours: &lt;a href="https://sqlite.org/forum/forummain"&gt;https://sqlite.org/forum/forummain&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;From Predrag Gruevski: Regarding learning curve, is a GraphQL web IDE (with syntax highlighting / autocomplete etc.) sufficiently user-friendly for folks more comfortable with a spreadsheet than a CLI tool or SQL?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Probably not! GraphQL requires thinking like a programmer too. I'm interested in helping people who aren't yet ready to learn any kind of programming language&lt;/li&gt;
&lt;li&gt;I have a plugin for Datasette that adds GraphQL with the GraphiQL user interface - demo here: &lt;a href="https://datasette-graphql-demo.datasette.io/graphql/github?query=%7B%0A%20%20issue_comments%20%7B%0A%20%20%20%20totalCount%0A%20%20%20%20pageInfo%20%7B%0A%20%20%20%20%20%20hasNextPage%0A%20%20%20%20%20%20endCursor%0A%20%20%20%20%7D%0A%20%20%20%20nodes%20%7B%0A%20%20%20%20%20%20html_url%0A%20%20%20%20%20%20issue_url%0A%20%20%20%20%20%20id%0A%20%20%20%20%20%20node_id%0A%20%20%20%20%20%20created_at%0A%20%20%20%20%20%20updated_at%0A%20%20%20%20%20%20author_association%0A%20%20%20%20%20%20body%0A%20%20%20%20%20%20reactions%0A%20%20%20%20%20%20performed_via_github_app%0A%20%20%20%20%20%20user%20%7B%0A%20%20%20%20%20%20%20%20id%0A%20%20%20%20%20%20%20%20name%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20issue%20%7B%0A%20%20%20%20%20%20%20%20id%0A%20%20%20%20%20%20%20%20title%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D"&gt;datasette-graphql-demo.datasette.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Thanks! Would love to compare notes on this -- my experience from working with analysts at my employer was that they were able to master GraphiQL very quickly. In a sense, it was more intimidating than actually difficult, so working with them directly to get them over the initial difficulty hump via examples and targeted exercises made a huge positive impact.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Litestream&lt;/h5&gt;
&lt;p&gt;Ben Johnson &lt;a href="https://twitter.com/benbjohnson"&gt;@benbjohnson&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://litestream.io/"&gt;Litestream&lt;/a&gt; adds replication to SQLite, allowing databases to be cheaply replicated to storage systems such as S3. Litestream also now implements live read-replication, where many read replicas can be run against a single leader database.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.sqlite.org/np1queryprob.html"&gt;https://www.sqlite.org/np1queryprob.html&lt;/a&gt; - Many Small Queries Are Efficient in SQLite&lt;/p&gt;
&lt;p&gt;Questions about Litestream:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;What does the planned hot standby feature look like, especially regarding durability guarantees during fail-over?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;BJ: Hot standby is a tough issue to generalize. The database-as-a-service version of Litestream that's coming will handle this but it's not necessarily planned for Litestream)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Will DBaaS be hosted, OSS, or both?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It'll be both&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;From Longwei Su: I assume offline update will be commit locally then sync with the online storage. If there is a offline commit that conflict with the online version(that already committed in). How to resolve the conflict?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Not sure if this relates to Litestream but; how big is sql.js --- how much does it cost (in kilobytes) to load sqlite in the browser?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;BJ: I think sql.js is 1.2MB so the cost depends on how much your provider charges for bandwidth&lt;/li&gt;
&lt;li&gt;Thanks! Meant "cost" in the sense of bytes transferred over wire --- this answers it :)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;GraphQL&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/simonw/help-scraper"&gt;https://github.com/simonw/help-scraper&lt;/a&gt; is scraping GraphQL schemas&lt;/li&gt;
&lt;/ul&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/my-talks"&gt;my-talks&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/twitter"&gt;twitter&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/litestream"&gt;litestream&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ben-johnson"&gt;ben-johnson&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/geoffrey-litt"&gt;geoffrey-litt&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="sqlite"/><category term="my-talks"/><category term="twitter"/><category term="datasette"/><category term="litestream"/><category term="ben-johnson"/><category term="geoffrey-litt"/></entry><entry><title>Quoting Ben Johnson</title><link href="https://simonwillison.net/2021/Feb/11/ben-johnson/#atom-tag" rel="alternate"/><published>2021-02-11T20:50:21+00:00</published><updated>2021-02-11T20:50:21+00:00</updated><id>https://simonwillison.net/2021/Feb/11/ben-johnson/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://news.ycombinator.com/item?id=26106043"&gt;&lt;p&gt;Litestream runs continuously on a test server with generated load and streams backups to S3. It uses physical replication so it'll actually restore the data from S3 periodically and compare the checksum byte-for-byte with the current database.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://news.ycombinator.com/item?id=26106043"&gt;Ben Johnson&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/testing"&gt;testing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/litestream"&gt;litestream&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ben-johnson"&gt;ben-johnson&lt;/a&gt;&lt;/p&gt;



</summary><category term="testing"/><category term="litestream"/><category term="ben-johnson"/></entry><entry><title>Why I Built Litestream</title><link href="https://simonwillison.net/2021/Feb/11/why-i-built-litestream/#atom-tag" rel="alternate"/><published>2021-02-11T19:25:26+00:00</published><updated>2021-02-11T19:25:26+00:00</updated><id>https://simonwillison.net/2021/Feb/11/why-i-built-litestream/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://litestream.io/blog/why-i-built-litestream/"&gt;Why I Built Litestream&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Litestream is a really exciting new piece of technology by Ben Johnson, who previously built BoltDB, the key-value store written in Go that is used by etcd. It adds replication to SQLite by running a process that converts the SQLite WAL log into a stream that can be saved to another folder or pushed to S3. The S3 option is particularly exciting—Ben estimates that keeping a full point-in-time recovery log of a high write SQLite database should cost in the order of a few dollars a month. I think this could greatly expand the set of use-cases for which SQLite is sensible choice.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/replication"&gt;replication&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/scaling"&gt;scaling&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ben-johnson"&gt;ben-johnson&lt;/a&gt;&lt;/p&gt;



</summary><category term="replication"/><category term="scaling"/><category term="sqlite"/><category term="ben-johnson"/></entry></feed>