rqlite 10.2.4
Overview
rqlite is a lightweight, fault-tolerant, distributed relational database built on SQLite with Raft consensus. It provides full SQL support (including FTS5, JSON1) in a single binary with no external dependencies. The architecture is:
- SQLite — storage engine (WAL mode,
SYNCHRONOUS=off; Raft provides durability)
- Raft — consensus via
hashicorp/raft for replication and leader election
- HTTP API — RESTful interface on port 4001 (default)
- Raft TCP — inter-node communication on port 4002 (default)
Three binaries are built: rqlited (server), rqlite (CLI client), rqbench (benchmarking).
Data Flow
- Writes: HTTP → Raft consensus → FSM applies to SQLite → response
- Reads: HTTP → consistency check → query SQLite → response
Quorum requires (N/2)+1 nodes: 3-node cluster tolerates 1 failure, 5-node tolerates 2.
Usage
Quick Start (Docker)
# Single node
docker run -d --name rqlite -p 4001:4001 -v rqlite:/rqlite/file rqlite/rqlite
# Query via HTTP
curl -XPOST 'localhost:4001/db/execute?pretty' \
-H 'Content-Type: application/json' \
-d '["CREATE TABLE foo (id INTEGER PRIMARY KEY, name TEXT)"]'
curl -G 'localhost:4001/db/query?pretty' --data-urlencode 'q=SELECT * FROM foo'
Quick Start (Binary)
# Download binary from https://github.com/rqlite/rqlite/releases/tag/v10.2.4
mkdir /opt/rqlite && tar xzf rqlite_linux_amd64.tar.gz -C /opt/rqlite
/opt/rqlite/rqlited -http-addr 0.0.0.0:4001 -raft-addr 0.0.0.0:4002 /data/rqlite
CLI Usage
# Connect to local node (default http://127.0.0.1:4001)
rqlite
# Connect to remote node
rqlite -H 10.0.0.1 -p 4001
# HTTPS with insecure skip
rqlite -s https -i -H 10.0.0.1 -p 4001
# With basic auth
rqlite -u admin:password -H 10.0.0.1 -p 4001
# Using RQLITE_HOST env var
RQLITE_HOST=https://10.0.0.1:4001 rqlite -i
Inside the CLI, use dot commands:
| Command |
Description |
.help |
List all commands |
.status |
Node status and diagnostics |
.nodes [all] |
Cluster topology; all includes non-voters |
.leader |
Current Raft leader |
.tables / .indexes / .schema |
Database introspection |
.backup FILE |
Hot backup to file |
.restore FILE |
Restore from SQLite file or SQL dump |
.boot FILE |
Boot node with SQLite file (single-node only) |
.dump FILE [TABLES] |
SQL text dump, optionally per-table |
.read FILE |
Execute SQL statements from file |
.consistency [level] |
Set/read consistency: none, weak, linearizable, strong |
.mode [column|csv|json|line] |
Output format |
.timer [on|off] |
Show query timing |
.remove NODEID |
Remove node from cluster |
.snapshot [TRAILING_LOGS] |
Trigger Raft snapshot |
.reap |
Reap old snapshots and checkpoint WALs |
.stepdown [NODEID] |
Leader stepdown, optionally to specific node |
.extensions |
Loaded SQLite extensions |
HTTP API Endpoints
| Endpoint |
Method |
Purpose |
/db/execute |
POST |
Write operations (INSERT, UPDATE, DELETE, CREATE) |
/db/query |
GET/POST |
Read operations (SELECT) |
/db/request |
POST |
Unified endpoint for reads and writes |
/db/backup |
GET |
Hot backup (SQLite binary or SQL dump) |
/db/load |
POST |
Load SQLite file or SQL dump into cluster |
/boot |
POST |
Boot single node with SQLite file |
/status |
GET |
Node status; use ?key=X to filter |
/readyz |
GET |
Readiness probe (200 = ready) |
/nodes |
GET |
Cluster topology (?nonvoters includes read-only) |
/leader |
GET/POST |
Get leader info or trigger stepdown |
/snapshot |
POST |
Trigger Raft snapshot (?trailing_logs=N) |
/reap |
POST |
Reap old snapshots |
/db/sql |
POST |
SQL analysis (EXPLAIN QUERY PLAN) |
Execute Request
# Single statement
curl -XPOST 'http://localhost:4001/db/execute' \
-H 'Content-Type: application/json' \
-d '{"statements": [{"sql": "CREATE TABLE t (id INTEGER PRIMARY KEY, v TEXT)"}]}'
# Multiple statements (atomic batch — single Raft entry)
curl -XPOST 'http://localhost:4001/db/execute?pretty' \
-H 'Content-Type: application/json' \
-d '[
"CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)",
"INSERT INTO users VALUES(1, ''alice'')"
]'
# With transaction wrapping
curl -XPOST 'http://localhost:4001/db/execute?transaction' \
-H 'Content-Type: application/json' -d '["UPDATE t SET v=1", "UPDATE t SET v=2"]'
# Queued writes (returns immediately, batched automatically — much higher throughput)
curl -XPOST 'http://localhost:4001/db/execute?queue' \
-H 'Content-Type: application/json' -d '["INSERT INTO t VALUES(1)"]'
# With timing info
curl -XPOST 'http://localhost:4001/db/execute?timings' \
-H 'Content-Type: application/json' -d '["SELECT * FROM t"]'
# Associative JSON output (column names as keys)
curl -XPOST 'http://localhost:4001/db/execute?associative' \
-H 'Content-Type: application/json' -d '["SELECT * FROM t"]'
# Include Raft index in response
curl -XPOST 'http://localhost:4001/db/execute?raft_index' \
-H 'Content-Type: application/json' -d '["INSERT INTO t VALUES(1)"]'
Query Request
# Basic query (use GET with url-encoded q parameter)
curl -G 'http://localhost:4001/db/query?pretty' --data-urlencode 'q=SELECT * FROM t'
# With consistency level
curl -G 'http://localhost:4001/db/query?level=linearizable' --data-urlencode 'q=SELECT * FROM t'
# POST with JSON body
curl -XPOST 'http://localhost:4001/db/query' \
-H 'Content-Type: application/json' \
-d '{"queries": [{"sql": "SELECT * FROM t"}]}'
# With freshness bound (for level=none)
curl -G 'http://localhost:4001/db/query?level=none&freshness=5s' --data-urlencode 'q=SELECT * FROM t'
# Qualify columns with table names
curl -G 'http://localhost:4001/db/query?qualify_columns' --data-urlencode 'q=SELECT * FROM t JOIN u ON t.id=u.id'
Read Consistency Levels
Set via ?level= query parameter or .consistency CLI command:
| Level |
Behavior |
Use Case |
weak (default) |
Checks local leadership state; ~1s staleness possible |
General purpose, best performance |
linearizable |
Verifies leadership via quorum heartbeat before read |
When reads must be up-to-date |
none |
Direct local read, no leader check; use ?freshness=5s to bound staleness |
Maximum read throughput |
strong |
Read goes through Raft log (slowest) |
Testing and debugging |
For level=none, use ?freshness=DURATION to ensure the node has been leader within that window. Add freshness_strict for strict enforcement.
Queued Writes
Append ?queue to /db/execute. Returns immediately; writes are batched and applied asynchronously. Default queue: capacity 1024, batch size 128, timeout 50ms. Configure with -write-queue-capacity, -write-queue-batch-size, -write-queue-timeout, -write-queue-tx.
Non-deterministic Functions
RANDOM() and datetime('now') are automatically rewritten before Raft log storage to ensure identical results across replicas. Disable rewriting with ?norwrandom or ?norwtime.
Gotchas
- HTTP and Raft addresses must use different ports — binding both to the same port fails validation. Use 4001/4002 convention.
- Advertised addresses must be routable —
0.0.0.0 is valid for bind but not for advertised address. Use -http-adv-addr and -raft-adv-addr in containers/Kubernetes.
/boot only works on single-node setups — it bypasses Raft. For clusters, use /db/load instead.
- Non-voting nodes cannot use CDC — Change Data Capture requires voting nodes only.
- DNS/dns-srv discovery requires
-bootstrap-expect N — voting nodes using DNS discovery must specify expected cluster size.
-join and -disco-mode are mutually exclusive — choose one clustering method.
- Auto-restore cannot be combined with
-join — a node either boots from backup or joins existing cluster.
- SQLite runs with
SYNCHRONOUS=off — durability comes from Raft fsync, not SQLite. Do not rely on SQLite-level durability guarantees.
RANDOM() and time functions are rewritten — results may differ from standalone SQLite. Use ?norwrandom/?norwtime if you need raw SQLite behavior.
- Queued writes trade durability for throughput — data is acknowledged before Raft commitment. A leader crash before commit could lose queued writes.
- Foreign keys are disabled by default — enable with
-fk flag on rqlited.
- mTLS requires both cert and key —
-http-cert and -http-key must be set together (same for node certs).
- CDC only captures INSERT/UPDATE/DELETE — DDL changes (CREATE, ALTER, DROP) are not captured.
- Backup with
?vacuum triggers VACUUM before backup — this blocks writes during vacuum; use carefully on busy nodes.
- Leader stepdown waits for new election by default (
?wait=true) — omit wait for immediate stepdown without waiting.
References
- 01-http-api — Full HTTP API reference with all query parameters and response formats
- 02-server-flags — Complete rqlited configuration flags reference
- 03-clustering — Clustering setup: manual join, DNS, Consul, etcd, Kubernetes
- 04-security — Authentication file format, TLS/mTLS configuration, permissions
- 05-backups — Backup strategies, auto-backup to S3/GCS/MinIO, restore procedures
- 06-cdc — Change Data Capture configuration and event format
- 07-extensions — Loading SQLite extensions (sqlite-vec, sqlean, sqliteai)
1---2name: rqlite-10-2-43description: Operate rqlite 10.2.4 — distributed SQLite database with Raft consensus. Use for deploying, configuring, querying, backing up, and managing rqlite clusters. Covers rqlited server flags, HTTP API (/db/execute, /db/query, /db/request), CLI (.status, .backup, .nodes), clustering (join, DNS, Consul, etcd, Kubernetes), TLS/mTLS auth, queued writes, CDC, consistency levels, and SQLite extensions. Use whenever the user mentions rqlite, distributed SQLite, Raft database, or needs a lightweight fault-tolerant relational store.4---56# rqlite 10.2.478## Overview910rqlite is a lightweight, fault-tolerant, distributed relational database built on SQLite with Raft consensus. It provides full SQL support (including FTS5, JSON1) in a single binary with no external dependencies. The architecture is:1112- **SQLite** — storage engine (WAL mode, `SYNCHRONOUS=off`; Raft provides durability)13- **Raft** — consensus via `hashicorp/raft` for replication and leader election14- **HTTP API** — RESTful interface on port 4001 (default)15- **Raft TCP** — inter-node communication on port 4002 (default)1617Three binaries are built: `rqlited` (server), `rqlite` (CLI client), `rqbench` (benchmarking).1819### Data Flow2021- **Writes**: HTTP → Raft consensus → FSM applies to SQLite → response22- **Reads**: HTTP → consistency check → query SQLite → response2324Quorum requires `(N/2)+1` nodes: 3-node cluster tolerates 1 failure, 5-node tolerates 2.2526## Usage2728### Quick Start (Docker)2930```bash31# Single node32docker run -d --name rqlite -p 4001:4001 -v rqlite:/rqlite/file rqlite/rqlite3334# Query via HTTP35curl -XPOST 'localhost:4001/db/execute?pretty' \36 -H 'Content-Type: application/json' \37 -d '["CREATE TABLE foo (id INTEGER PRIMARY KEY, name TEXT)"]'3839curl -G 'localhost:4001/db/query?pretty' --data-urlencode 'q=SELECT * FROM foo'40```4142### Quick Start (Binary)4344```bash45# Download binary from https://github.com/rqlite/rqlite/releases/tag/v10.2.446mkdir /opt/rqlite && tar xzf rqlite_linux_amd64.tar.gz -C /opt/rqlite47/opt/rqlite/rqlited -http-addr 0.0.0.0:4001 -raft-addr 0.0.0.0:4002 /data/rqlite48```4950### CLI Usage5152```bash53# Connect to local node (default http://127.0.0.1:4001)54rqlite5556# Connect to remote node57rqlite -H 10.0.0.1 -p 40015859# HTTPS with insecure skip60rqlite -s https -i -H 10.0.0.1 -p 40016162# With basic auth63rqlite -u admin:password -H 10.0.0.1 -p 40016465# Using RQLITE_HOST env var66RQLITE_HOST=https://10.0.0.1:4001 rqlite -i67```6869Inside the CLI, use dot commands:7071| Command | Description |72|---|---|73| `.help` | List all commands |74| `.status` | Node status and diagnostics |75| `.nodes [all]` | Cluster topology; `all` includes non-voters |76| `.leader` | Current Raft leader |77| `.tables` / `.indexes` / `.schema` | Database introspection |78| `.backup FILE` | Hot backup to file |79| `.restore FILE` | Restore from SQLite file or SQL dump |80| `.boot FILE` | Boot node with SQLite file (single-node only) |81| `.dump FILE [TABLES]` | SQL text dump, optionally per-table |82| `.read FILE` | Execute SQL statements from file |83| `.consistency [level]` | Set/read consistency: none, weak, linearizable, strong |84| `.mode [column\|csv\|json\|line]` | Output format |85| `.timer [on\|off]` | Show query timing |86| `.remove NODEID` | Remove node from cluster |87| `.snapshot [TRAILING_LOGS]` | Trigger Raft snapshot |88| `.reap` | Reap old snapshots and checkpoint WALs |89| `.stepdown [NODEID]` | Leader stepdown, optionally to specific node |90| `.extensions` | Loaded SQLite extensions |9192### HTTP API Endpoints9394| Endpoint | Method | Purpose |95|---|---|---|96| `/db/execute` | POST | Write operations (INSERT, UPDATE, DELETE, CREATE) |97| `/db/query` | GET/POST | Read operations (SELECT) |98| `/db/request` | POST | Unified endpoint for reads and writes |99| `/db/backup` | GET | Hot backup (SQLite binary or SQL dump) |100| `/db/load` | POST | Load SQLite file or SQL dump into cluster |101| `/boot` | POST | Boot single node with SQLite file |102| `/status` | GET | Node status; use `?key=X` to filter |103| `/readyz` | GET | Readiness probe (200 = ready) |104| `/nodes` | GET | Cluster topology (`?nonvoters` includes read-only) |105| `/leader` | GET/POST | Get leader info or trigger stepdown |106| `/snapshot` | POST | Trigger Raft snapshot (`?trailing_logs=N`) |107| `/reap` | POST | Reap old snapshots |108| `/db/sql` | POST | SQL analysis (EXPLAIN QUERY PLAN) |109110### Execute Request111112```bash113# Single statement114curl -XPOST 'http://localhost:4001/db/execute' \115 -H 'Content-Type: application/json' \116 -d '{"statements": [{"sql": "CREATE TABLE t (id INTEGER PRIMARY KEY, v TEXT)"}]}'117118# Multiple statements (atomic batch — single Raft entry)119curl -XPOST 'http://localhost:4001/db/execute?pretty' \120 -H 'Content-Type: application/json' \121 -d '[122 "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)",123 "INSERT INTO users VALUES(1, ''alice'')"124 ]'125126# With transaction wrapping127curl -XPOST 'http://localhost:4001/db/execute?transaction' \128 -H 'Content-Type: application/json' -d '["UPDATE t SET v=1", "UPDATE t SET v=2"]'129130# Queued writes (returns immediately, batched automatically — much higher throughput)131curl -XPOST 'http://localhost:4001/db/execute?queue' \132 -H 'Content-Type: application/json' -d '["INSERT INTO t VALUES(1)"]'133134# With timing info135curl -XPOST 'http://localhost:4001/db/execute?timings' \136 -H 'Content-Type: application/json' -d '["SELECT * FROM t"]'137138# Associative JSON output (column names as keys)139curl -XPOST 'http://localhost:4001/db/execute?associative' \140 -H 'Content-Type: application/json' -d '["SELECT * FROM t"]'141142# Include Raft index in response143curl -XPOST 'http://localhost:4001/db/execute?raft_index' \144 -H 'Content-Type: application/json' -d '["INSERT INTO t VALUES(1)"]'145```146147### Query Request148149```bash150# Basic query (use GET with url-encoded q parameter)151curl -G 'http://localhost:4001/db/query?pretty' --data-urlencode 'q=SELECT * FROM t'152153# With consistency level154curl -G 'http://localhost:4001/db/query?level=linearizable' --data-urlencode 'q=SELECT * FROM t'155156# POST with JSON body157curl -XPOST 'http://localhost:4001/db/query' \158 -H 'Content-Type: application/json' \159 -d '{"queries": [{"sql": "SELECT * FROM t"}]}'160161# With freshness bound (for level=none)162curl -G 'http://localhost:4001/db/query?level=none&freshness=5s' --data-urlencode 'q=SELECT * FROM t'163164# Qualify columns with table names165curl -G 'http://localhost:4001/db/query?qualify_columns' --data-urlencode 'q=SELECT * FROM t JOIN u ON t.id=u.id'166```167168### Read Consistency Levels169170Set via `?level=` query parameter or `.consistency` CLI command:171172| Level | Behavior | Use Case |173|---|---|---|174| `weak` (default) | Checks local leadership state; ~1s staleness possible | General purpose, best performance |175| `linearizable` | Verifies leadership via quorum heartbeat before read | When reads must be up-to-date |176| `none` | Direct local read, no leader check; use `?freshness=5s` to bound staleness | Maximum read throughput |177| `strong` | Read goes through Raft log (slowest) | Testing and debugging |178179For `level=none`, use `?freshness=DURATION` to ensure the node has been leader within that window. Add `freshness_strict` for strict enforcement.180181### Queued Writes182183Append `?queue` to `/db/execute`. Returns immediately; writes are batched and applied asynchronously. Default queue: capacity 1024, batch size 128, timeout 50ms. Configure with `-write-queue-capacity`, `-write-queue-batch-size`, `-write-queue-timeout`, `-write-queue-tx`.184185### Non-deterministic Functions186187`RANDOM()` and `datetime('now')` are automatically rewritten before Raft log storage to ensure identical results across replicas. Disable rewriting with `?norwrandom` or `?norwtime`.188189## Gotchas190191- **HTTP and Raft addresses must use different ports** — binding both to the same port fails validation. Use 4001/4002 convention.192- **Advertised addresses must be routable** — `0.0.0.0` is valid for bind but not for advertised address. Use `-http-adv-addr` and `-raft-adv-addr` in containers/Kubernetes.193- **`/boot` only works on single-node setups** — it bypasses Raft. For clusters, use `/db/load` instead.194- **Non-voting nodes cannot use CDC** — Change Data Capture requires voting nodes only.195- **DNS/dns-srv discovery requires `-bootstrap-expect N`** — voting nodes using DNS discovery must specify expected cluster size.196- **`-join` and `-disco-mode` are mutually exclusive** — choose one clustering method.197- **Auto-restore cannot be combined with `-join`** — a node either boots from backup or joins existing cluster.198- **SQLite runs with `SYNCHRONOUS=off`** — durability comes from Raft fsync, not SQLite. Do not rely on SQLite-level durability guarantees.199- **`RANDOM()` and time functions are rewritten** — results may differ from standalone SQLite. Use `?norwrandom`/`?norwtime` if you need raw SQLite behavior.200- **Queued writes trade durability for throughput** — data is acknowledged before Raft commitment. A leader crash before commit could lose queued writes.201- **Foreign keys are disabled by default** — enable with `-fk` flag on `rqlited`.202- **mTLS requires both cert and key** — `-http-cert` and `-http-key` must be set together (same for node certs).203- **CDC only captures INSERT/UPDATE/DELETE** — DDL changes (CREATE, ALTER, DROP) are not captured.204- **Backup with `?vacuum` triggers VACUUM before backup** — this blocks writes during vacuum; use carefully on busy nodes.205- **Leader stepdown waits for new election by default** (`?wait=true`) — omit `wait` for immediate stepdown without waiting.206207## References208209- [01-http-api](references/01-http-api.md) — Full HTTP API reference with all query parameters and response formats210- [02-server-flags](references/02-server-flags.md) — Complete rqlited configuration flags reference211- [03-clustering](references/03-clustering.md) — Clustering setup: manual join, DNS, Consul, etcd, Kubernetes212- [04-security](references/04-security.md) — Authentication file format, TLS/mTLS configuration, permissions213- [05-backups](references/05-backups.md) — Backup strategies, auto-backup to S3/GCS/MinIO, restore procedures214- [06-cdc](references/06-cdc.md) — Change Data Capture configuration and event format215- [07-extensions](references/07-extensions.md) — Loading SQLite extensions (sqlite-vec, sqlean, sqliteai)