Discovery
Back to browse

rqlite - fault-tolerant DB on SQLite

Distributed, fault-tolerant SQL database built around SQLite using Raft consensus. v10 adds a built-in web console and CRC32 integrity checks throughout.

4 min readView source ↗

rqlite is the answer to "I want etcd, but I also want SQL." It's a fault-tolerant distributed relational database built on SQLite, with Raft consensus wrapping the storage layer. The pitch that lands: a single binary, no external dependencies, up and running in seconds, and you get a full SQL surface (FTS5, JSON1, extensions) backed by SQLite's famously well-tested engine.

The use cases the README leans into are the right ones. Resilient services in the cloud where you need a small, replicated SQL store and don't want to operate Postgres for it. Reliable applications at the edge where SQLite is already the right answer but you need replication. Configuration and metadata stores that have outgrown a single file but haven't earned a dedicated cluster.

Quick start

A single Docker command brings up a node:

docker run -p 4001:4001 rqlite/rqlite

Create a table and insert a row over the HTTP API:

curl -XPOST 'localhost:4001/db/execute?pretty' -H 'Content-Type: application/json' -d '[
     "CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)",
     "INSERT INTO foo(id, name) VALUES(1, \"fiona\")"
]'

Query:

curl -G 'localhost:4001/db/query?pretty' --data-urlencode 'q=SELECT * FROM foo'

That's the whole interface. The HTTP API is the primary surface; there's also a CLI and a built-in web console (added in v10) plus client libraries for the usual languages.

Why this is interesting

Three properties stack:

Real SQL via SQLite. This isn't a key-value store with a SQL-shaped DSL on top - it's actual SQLite, which means FTS5 full-text search, JSON1 functions, and the loadable-extension ecosystem (vector search via sqlite-vec, cryptography via sqlean, R-Tree, and so on) all just work.

Atomic requests. Multiple SQL statements in a single API call execute atomically. The transaction boundary is the request, which removes the need for an explicit BEGIN/COMMIT round-trip dance that a lot of HTTP-fronted SQL services get wrong.

Tunable consistency. Raft gives you a strongly-consistent default, but the read path is configurable: weak / linearizable / strong. Writes can be queued for higher throughput when durability semantics allow it. This is the knob that distinguishes "I want etcd's correctness" from "I want a distributed SQLite that's fast enough for hot reads."

Operations story

The thing rqlite cares more about than most distributed databases is being easy to run:

  • Single binary, no external dependencies. The Docker image is the same binary in a thin wrapper.
  • Dynamic clustering via Kubernetes, Docker Compose, Consul, etcd, or DNS - bring your own discovery, rqlite figures out the rest.
  • Hot backups with automatic upload to S3, MinIO, or GCS. Restore from a plain SQLite file or from a cloud-stored backup.
  • TLS end to end plus authentication and authorization controls.
  • Change data capture - stream changes to an external system if you want to fan out the SQL state to other infrastructure.

v10 added a built-in web console and CRC32 integrity checks throughout the storage layer. The integrity checks are the sort of thing that doesn't show up in headline announcements but matters the day you have a corrupted disk on one node.

When to reach for it

  • You need a fault-tolerant SQL store but Postgres or MySQL is heavier than the workload deserves.
  • You're already running SQLite at the edge and want replication without changing your query model.
  • You want etcd-style strong consistency on configuration data, plus the ability to run real queries against it.
  • Agent harnesses and developer-tool infrastructure that need a small, embedded-feeling, replicated relational store.

When not to

  • High-write OLTP workloads. Raft consensus serializes writes through the leader; write throughput is bounded by Raft round-trips, not by SQLite's local performance. If you're benchmarking 50k writes/sec, look elsewhere.
  • Massive datasets. SQLite is happy at gigabytes, occasionally happy at low hundreds of gigabytes; rqlite inherits that ceiling.
  • Workloads that already have a Postgres operator and want one more service. The win is when the operational overhead matters; if you're already running a cluster anyway, the case is weaker.

Trade-offs worth knowing

Read consistency is per-request, but most clients default to "weak" (read from the local node, no Raft round-trip). That's fast and correct for most use cases - until you hit the corner case where a write you just made isn't visible on the node you're reading from. Either pin reads to the leader, set the consistency level explicitly per query, or use queued writes if you'd rather trade durability for throughput.

The HTTP-only API is a feature for portability and a constraint for performance - there's no binary protocol with persistent connections in the standard surface. For most use cases this is a non-issue; for high-frequency hot paths, batch your statements into single atomic requests rather than chattering.

MIT licensed, written in Go. Maintained by Philip O'Toole; the project's testing approach (linked from the README, "How is rqlite tested?") is worth reading on its own merits if you care about how distributed databases earn trust.

Recent discussion

From the wider web

Featured in

Related entries