LiteFS replicates SQLite transactions through a filesystem
LiteFS enters public beta with a FUSE filesystem that observes SQLite transaction boundaries. Its design preserves local reads while making asynchronous replication and primary selection explicit.
An application using SQLite can read its database through local library calls, but giving another machine a usable copy requires a replication mechanism. LiteFS enters public beta today, September 21, with a filesystem that observes transaction boundaries and packages changed pages for replicas. It places replication below the application's database API. The existing SQLite library can continue opening and querying a file while LiteFS tracks the changes passing through the mount.
The filesystem choice is the distinguishing part of the design. SQLite has a virtual filesystem interface, but making each process load a special implementation would add a configuration requirement wherever the database is opened. A FUSE mount gives processes one shared interception point. Applications use the database path, and LiteFS can run its replication service independently of those processes.
I value SQLite because reading a local database does not require a database-server round trip. LiteFS tries to preserve that property across a deployment with several application instances. Its beta design also makes a deliberate asynchronous replication tradeoff, so understanding the primary and recovery rules matters as much as understanding local reads.
A transaction becomes a portable change set
The architecture document published with the announcement describes a write transaction as changes to database pages, protected by SQLite's journaling machinery. LiteFS packages the changed pages in Lite Transaction files, or LTX files. Each has an increasing transaction identifier, which gives a replica a position in the primary's history.
The beta supports rollback-journal mode. During a write, SQLite copies old page contents to the journal and updates the main database. LiteFS passes the filesystem operations through to underlying storage. When the journal is deleted to complete the transaction, LiteFS intercepts that operation and converts the updated pages into an LTX file.
This gives replication a unit corresponding to a transaction's page changes. It also means the implementation depends on the journaling mode it understands. WAL support appears as future work in the contemporaneous design. A deployment cannot assume that every SQLite mode supported by the library is already supported through the beta filesystem.
The LTX design sorts pages for compaction and attaches checksums to the change set. It also associates each transaction position with a checksum representing the database state. These fields let the replication process ask more than which transaction number a replica has seen. It can also ask whether that number describes the same database contents.
The mount enforces the primary distinction
The filesystem permits writes on the primary and protects replica databases from writes. It exposes information about the current primary through a .primary file. This makes primary identity available to an application that needs to direct a state-changing request to the writable node.
The beta design therefore retains a distinction between reading a local copy and changing authoritative state. A local replica is useful for queries, but its presence does not make it an independent writer. Automatic write forwarding is described as future work in the announcement. An application architecture using this beta has to account for where writes execute.
That division can be appropriate for read-heavy applications. Several instances can evaluate queries against their local copies, while the single primary accepts changes. The benefit depends on how those requests use data. A request that only needs a sufficiently current local copy differs from one that must observe a change just accepted elsewhere.
Placing the replication mechanism beneath SQL reduces changes to database access code, but it cannot choose every application consistency requirement. The program still needs to know whether a particular operation can use a replica. Filesystem transparency concerns access mechanics, while a request's meaning determines which state it needs to read.
A lease selects the writable node
The architecture uses Consul sessions for primary selection. A candidate obtains a time-based lease associated with a key and renews it while operating as primary. A clean shutdown can release the lease so another node becomes primary. After an unexpected failure, the lease's time-to-live must expire before a replacement takes over.
This creates different failover timing for planned and unplanned transitions. A deployment that deliberately stops its primary can cooperate in releasing ownership. A failed process cannot perform that cleanup, so the lease mechanism supplies a time limit on its claim. The distinction follows directly from the ownership mechanism.
Replicas need not all be at the same transaction position when a new primary is selected. The design explicitly states that the elected primary determines the database state. A replica that had received more recent transactions can consequently lose those transactions when reconciling with the new primary. Selecting a writer and preserving every acknowledged transaction are separate guarantees.
This is a substantive tradeoff for a system intended to make replicated SQLite simple to operate. A lease can establish which node should accept writes while asynchronous transfer still leaves a gap between the primary's state and a replica's state. The design does not claim that primary election closes that gap.
Replica recovery uses both position and contents
Replicas communicate with the primary over HTTP. On connection, a replica supplies its transaction identifier and rolling database checksum. The primary streams changes starting from that position when it still retains the required history. If that history is unavailable, it supplies a snapshot and continues replication from the snapshot state.
The checksum matters when two nodes have diverged. Consider an old primary that accepted writes during a period when it could not replicate them. A new primary may now have its own history. Equal transaction numbers alone would not prove that the two database files represent the same state. Applying a change set that assumes different starting bytes can damage the result.
LiteFS compares the represented state and resnapshots when the old primary's state differs from the new primary's state. That chooses one authoritative history and replaces the divergent copy. It protects the resulting file from blindly combining incompatible page changes. It does not merge the application meaning of transactions that existed only on the displaced primary.
The difference between detecting divergence and preserving every write is central to this design. A checksum can establish that a replica does not have the expected starting state. Recovery can then replace its contents with a coherent snapshot. Neither operation recovers a transaction absent from the selected primary's history.
The checksum can be maintained per changed page
The architecture describes the rolling checksum as a combination of page checksums. For each page, LiteFS computes a CRC64 using the page number and contents. XOR combines those values into the database checksum. When a page changes, the old page's contribution is XORed out and the new page's contribution is XORed in.
That method avoids rereading the entire database for every transaction. Its work follows the changed pages whose old and new values are available through transaction processing. Including the page number means the represented state accounts for where the page contents belong. The same combination can be recomputed from the full file when checking it independently, giving recovery another way to compare the stored bytes with the recorded state.
This is an integrity mechanism for a known replication format and starting state. It does not make asynchronous replication synchronous. A replica can be internally coherent and still be behind the primary. Keeping those properties separate makes the system's guarantees easier to assess.
Durability depends on when replication happens
The contemporaneous architecture explicitly identifies a window in which a transaction is durable only on the primary. Catastrophic loss of that primary can lose the transaction before any replica has received it. Synchronous replication and bounded asynchronous replication are future directions, rather than guarantees provided by the beta.
This gives an application owner a concrete choice. Local SQLite reads and an independently managed filesystem can reduce database-access overhead and deployment coupling. In exchange, the asynchronous design requires accepting a possible loss window and understanding how primary selection determines the surviving history. Those consequences follow from the documented mechanism, without needing a benchmark or a hypothetical availability claim.
I find the design useful because its components have identifiable responsibilities. The mount observes writes, LTX represents page changes, and the lease selects the writable node. Replica recovery uses a snapshot when its history cannot safely continue. For an application that accepts the beta's asynchronous guarantees, these mechanisms preserve local querying while giving each replica a defined way to follow the primary's database state.