Imagina o cenário: seu app usa SQLite, funciona perfeitamente, é rápido, é simples, o arquivo fica ali do lado. Até que um dia o servidor morre. E junto com ele, seus dados. Parece dramático? É porque é. E esse problema foi resolvido em 2014. Só que quase ninguém ficou sabendo.
O SQLite distribuído não é conceito novo. O rqlite, o primeiro projeto open source que encapsulou o SQLite num cluster tolerante a falhas, completou 12 anos de existência. Doze anos. Na mesma época em que a gente ainda discutia se Docker era coisa séria, um desenvolvedor chamado Philip O’Toole já estava replicando SQLite entre múltiplos nós com consenso Raft.
E desde então, uma constelação inteira de projetos surgiu ao redor dessa mesma ideia: dqlite, Litestream, cr-sqlite, libSQL, Turso, Cloudflare D1. Cada um com uma abordagem diferente, cada um resolvendo um pedaço diferente do problema. Mas todos partindo da mesma premissa: o SQLite é bom demais pra ficar preso num único servidor.
Neste texto, eu vou te mostrar como esse ecossistema evoluiu, o que cada ferramenta faz de verdade, quando usar cada uma, e por que você provavelmente deveria estar prestando atenção nisso agora.
O que é SQLite distribuído, afinal?
Antes de qualquer coisa, vamos alinhar conceitos. O SQLite “normal” é um banco de dados embutido. Ele roda dentro do seu processo, grava num único arquivo, e não tem servidor. Isso é uma vantagem absurda pra simplicidade, mas cria um problema óbvio: se aquele arquivo se corrompe, se o disco morre, ou se o servidor desliga, acabou.
SQLite distribuído é qualquer solução que replica os dados do SQLite entre múltiplos nós, de forma que a perda de um (ou mais) nós não significa a perda dos dados. Parece simples? A engenharia por trás é qualquer coisa menos simples.
Existem basicamente três abordagens pra resolver isso:
| Abordagem | Exemplo | Consistência | Múltiplos writers? | Complexidade |
|---|---|---|---|---|
| Consenso (Raft) | rqlite, dqlite | Forte (CP) | Não, só o líder | Média |
| Streaming do WAL | Litestream | Eventual | Não, um writer | Baixa |
| CRDTs | cr-sqlite | Eventual (AP) | Sim | Alta |
Cada uma tem tradeoffs reais. Não existe bala de prata aqui.
rqlite: o pioneiro que ninguém conhece
Philip O’Toole publicou o rqlite em 2014 com uma ideia que cabe em uma frase: “pegar o SQLite, colocar um log Raft na frente, e replicar cada escrita pra um cluster, de forma que perder um nó não significasse perder os dados.”
A arquitetura é elegante na simplicidade. Cada nó do cluster tem sua própria instância do SQLite. Todas as escritas passam pelo nó líder, que registra o comando no log Raft. Quando a maioria dos nós confirma que recebeu o comando, ele é aplicado. Se o líder morre, o Raft elege um novo líder automaticamente.
# Subindo um cluster rqlite com 3 nós
rqlited -node-id 1 -http-addr localhost:4001 -raft-addr localhost:4002 ~/node.1
rqlited -node-id 2 -http-addr localhost:4003 -raft-addr localhost:4004 \
-join http://localhost:4001 ~/node.2
rqlited -node-id 3 -http-addr localhost:4005 -raft-addr localhost:4006 \
-join http://localhost:4001 ~/node.3
Depois disso, qualquer escrita via HTTP é replicada automaticamente:
# Inserindo dados via API REST
curl -XPOST 'localhost:4001/db/execute?pretty&timings' \
-H "Content-Type: application/json" \
-d '[
"CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)",
"INSERT INTO users(name, email) VALUES(\"Maria\", \"maria@dev.com\")"
]'
{
"results": [
{ "last_insert_id": 0, "rows_affected": 0, "time": 0.000281 },
{ "last_insert_id": 1, "rows_affected": 1, "time": 0.000055 }
],
"time": 0.012345
}
Uma coisa que eu acho particularmente interessante no rqlite é a API HTTP nativa. Não precisa de driver, não precisa de SDK. Um curl resolve. Isso é muito útil em cenários de automação, scripts, e ambientes onde instalar dependências é um problema.
Níveis de consistência nas leituras
O rqlite oferece três níveis de consistência pra leituras, e entender isso é crucial:
# Leitura "none" (mais rápida, pode ler dados stale)
curl 'localhost:4001/db/query?level=none&pretty' \
-d '["SELECT * FROM users"]'
# Leitura "weak" (confirma que o líder ainda é líder)
curl 'localhost:4001/db/query?level=weak&pretty' \
-d '["SELECT * FROM users"]'
# Leitura "strong" (garante linearizabilidade via Raft)
curl 'localhost:4001/db/query?level=strong&pretty' \
-d '["SELECT * FROM users"]'
| Nível | Latência | Garantia | Quando usar |
|---|---|---|---|
| none | ~1ms | Pode ler dados antigos | Dashboards, métricas |
| weak | ~2ms | Líder provavelmente atual | Maioria dos casos |
| strong | ~5-10ms | Linearizável | Transações financeiras |
Depois de mais de 10 anos em produção, o rqlite reportou menos de 10 panics. Dez. Em uma década. Isso diz muito sobre a estabilidade da implementação.
dqlite: a versão embutida da Canonical
Se o rqlite é um servidor que você roda, o dqlite é uma biblioteca que você embute no seu aplicativo. Criado pela Canonical em 2016, ele usa a mesma ideia (SQLite + Raft), mas empacotado como uma lib C que você integra diretamente no código.
O caso de uso mais famoso? O LXD, sistema de containers da Canonical. E o MicroK8s, distribuição leve do Kubernetes. Ambos usam dqlite internamente pra armazenar estado de forma distribuída sem depender de um banco externo.
// Exemplo simplificado de uso do dqlite em C
#include <dqlite.h>
dqlite_node *node;
dqlite_node_create(1, "127.0.0.1:9001", "/var/lib/dqlite", &node);
dqlite_node_start(node);
A diferença prática é: com rqlite, você faz HTTP requests pra um serviço separado. Com dqlite, o banco está dentro do seu processo. Menos latência de rede, mas mais complexidade de integração.
Litestream: replicação sem cluster
Em 2021, Ben Johnson (o mesmo criador do BoltDB) lançou o Litestream com uma filosofia completamente diferente: em vez de montar um cluster Raft, por que não simplesmente copiar o WAL (Write-Ahead Log) do SQLite pra um storage externo?
# Replicando SQLite para S3 em tempo real
litestream replicate /path/to/db.sqlite s3://meu-bucket/backups/
# Restaurando de um backup
litestream restore -o /path/to/restored.db s3://meu-bucket/backups/
É disaster recovery, não alta disponibilidade. O writer continua sendo único. Se ele morre, você precisa subir outro e restaurar do backup. Mas a simplicidade é imbatível: nenhum cluster pra gerenciar, nenhum Raft pra entender, nenhuma eleição de líder.
Pra aplicações que rodam num único servidor e só precisam garantir que os dados não se perdem, o Litestream resolve o problema com uma fração da complexidade.
cr-sqlite: CRDTs e o futuro local-first
Aqui as coisas ficam realmente interessantes. Em 2022, Matt Wonlaw criou o cr-sqlite, uma extensão que adiciona CRDTs (Conflict-free Replicated Data Types) ao SQLite. Traduzindo: múltiplos writers podem modificar o mesmo banco de dados simultaneamente, e os conflitos são resolvidos automaticamente na hora do merge.
Isso é o canto AP (Available + Partition tolerant) do teorema CAP. Enquanto o rqlite sacrifica disponibilidade pra manter consistência forte, o cr-sqlite sacrifica consistência forte pra manter disponibilidade total.
-- Transformando uma tabela normal em CRDT-aware
SELECT crsql_as_crr('users');
-- Depois disso, mudanças em qualquer réplica podem ser mergeadas
-- sem conflito, usando o clock lógico interno
SELECT * FROM crsql_changes() WHERE db_version > ?;
O caso de uso perfeito? Apps local-first. Pense em editores colaborativos, apps mobile que funcionam offline, ferramentas de notas distribuídas. Cada dispositivo tem sua cópia do SQLite, faz mudanças livremente, e quando reconecta, o merge acontece sem intervenção humana.
libSQL e Turso: quando Big Tech entra no jogo
Em 2022, a ChiselStrike fez algo que muita gente achava impossível: forkaram o SQLite. O motivo? O SQLite não aceita contribuições externas. O código é domínio público, mas o desenvolvimento é fechado num grupo seleto de committers.
O fork se chamou libSQL, e sobre ele nasceu a Turso: uma plataforma de SQLite distribuído na edge. A proposta é ter um banco primário (pra escritas) e réplicas de leitura espalhadas por mais de 200 pontos de presença globais, com latência abaixo de 100ms pras leituras.
# Criando um banco no Turso
turso db create meu-app
# Usando via CLI
turso db shell meu-app
> CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT, price REAL);
> INSERT INTO products VALUES (1, 'Widget', 29.90);
// SDK do Turso/libSQL para aplicações edge
import { createClient } from '@libsql/client';
const db = createClient({
url: 'libsql://meu-app-usuario.turso.io',
authToken: 'token-aqui'
});
const result = await db.execute('SELECT * FROM products WHERE price < ?', [50]);
Em 2026, a Supabase adquiriu a Turso. Isso não é detalhe pequeno. A Supabase, que construiu sua reputação como “Firebase open source” em cima do PostgreSQL, agora tem um SQLite distribuído no portfólio. O sinal é claro: SQLite na edge virou mainstream.
Cloudflare D1: SQLite serverless de verdade
A Cloudflare entrou no jogo com o D1, um banco SQLite que roda nativamente nos Workers. Sem servidor pra gerenciar, sem conexão TCP, sem pool de conexões. O banco está lá, na mesma edge que seu código, respondendo em microsegundos.
// Worker do Cloudflare com D1
export default {
async fetch(request, env) {
const { results } = await env.DB.prepare(
"SELECT * FROM users WHERE active = ?"
).bind(1).all();
return Response.json(results);
}
};
Se você já usa Cloudflare Workers, o D1 é a escolha natural. A integração é nativa, o billing é por operação, e você não precisa pensar em infraestrutura de banco.
Comparativo: qual usar e quando
Essa é a pergunta que todo mundo faz. E a resposta depende do seu cenário:
| Solução | Tipo | Melhor pra | Evitar quando |
|---|---|---|---|
| rqlite | Servidor, self-hosted | Alta disponibilidade simples, IoT, edge | Precisa de milhões de writes/s |
| dqlite | Lib embutida | Aplicações Go/C que precisam de DB distribuído | Não usa Go/C |
| Litestream | Backup contínuo | Apps com único writer que precisam de DR | Precisa de failover automático |
| cr-sqlite | CRDT extension | Apps local-first, offline-first | Precisa de consistência forte |
| Turso/libSQL | Plataforma edge | Leituras globais de baixa latência | Budget apertado, writes pesados |
| Cloudflare D1 | Serverless | Apps em Cloudflare Workers | Não usa Cloudflare |
Por que o SQLite está dominando?
Tem uma tendência clara acontecendo. O SQLite, que por décadas foi “aquele banco de testes” ou “aquele banco do celular”, está virando primeira opção pra produção. E os números explicam por quê.
Num benchmark recente, o SQLite em modo WAL mostrou latência de leitura 4.9x menor que o MySQL pra queries simples. Pra aplicações read-heavy (e a maioria é), isso é uma diferença absurda. (Sobre bancos analíticos, veja também nosso artigo sobre o DuckDB 2.0.) Sem servidor separado, sem conexão TCP, sem overhead de protocolo.
O DHH (sim, o criador do Rails) migrou apps em produção pro SQLite. O Laravel tem suporte nativo ao SQLite como banco principal desde o Laravel 11. O Bun (runtime JavaScript) tem suporte a SQLite built-in. O Turso integra com todos os frameworks populares.
A pergunta não é mais “por que usar SQLite em produção?”. É “por que NÃO usar?”.
Quando NÃO usar SQLite distribuído
Vou ser direto. SQLite distribuído não é pra tudo.
Se você precisa de múltiplos writers com consistência forte e baixa latência, PostgreSQL com streaming replication ainda é a melhor opção. Se você precisa de sharding horizontal com petabytes de dados, CockroachDB ou Vitess fazem mais sentido.
O rqlite, por exemplo, é explícito sobre isso: o objetivo é alta disponibilidade, não performance. As escritas são mais lentas que um SQLite standalone, porque cada write precisa do round-trip Raft. Se seu gargalo é write throughput, replicar SQLite não vai resolver.
Outro ponto: o SQLite tem um limite prático de tamanho. Bancos acima de 1TB começam a ficar impraticáveis. Se você está nessa escala, precisa de outra solução.
Como começar com rqlite hoje
Se bateu a curiosidade e você quer testar, é ridiculamente fácil:
# Instalar o rqlite (Linux)
curl -L https://github.com/rqlite/rqlite/releases/download/v8.36.8/rqlite-v8.36.8-linux-amd64.tar.gz \
-o rqlite.tar.gz
tar xvfz rqlite.tar.gz
cd rqlite-v8.36.8-linux-amd64
# Subir um nó standalone pra testar
./rqlited ~/node.1
# Em outro terminal, usar o CLI
./rqlite
> CREATE TABLE teste (id INTEGER PRIMARY KEY, msg TEXT);
> INSERT INTO teste(msg) VALUES("funciona!");
> SELECT * FROM teste;
Cinco minutos pra ter um banco distribuído rodando. Sem Docker, sem Kubernetes, sem YAML. Só um binário.
Pra produção, você vai querer pelo menos 3 nós (pra ter quórum) e configurar TLS:
# Nó 1 (líder inicial)
./rqlited -node-id 1 \
-http-addr 0.0.0.0:4001 \
-raft-addr 0.0.0.0:4002 \
-http-cert server.crt \
-http-key server.key \
~/node.1
# Nó 2 (junta ao cluster)
./rqlited -node-id 2 \
-http-addr 0.0.0.0:4003 \
-raft-addr 0.0.0.0:4004 \
-join https://node1:4001 \
~/node.2
12 anos depois, o que aprendemos?
A trajetória do SQLite distribuído prova algo que muitos engenheiros esquecem: a melhor infraestrutura é a que você entende completamente. O rqlite tem um codebase que um desenvolvedor solo consegue ler em um fim de semana. Compara isso com o CockroachDB ou o TiDB.
Philip O’Toole mantém o rqlite como projeto pessoal há 12 anos. Sem VC money, sem empresa por trás, sem marketing. E o projeto continua sendo usado em produção por empresas que preferem rodar seus próprios bancos a depender de SaaS.
Enquanto isso, o ecossistema ao redor explodiu. Turso levantou dezenas de milhões em venture capital, foi adquirida pela Supabase, e o conceito de “SQLite na edge” virou uma categoria de produto. O Cloudflare D1 processou bilhões de queries. O Litestream é usado em milhares de deploys.
E tudo começou com um cara que pensou: “e se eu colocasse um Raft na frente do SQLite?”. Doze anos e a ideia original continua intacta. Às vezes, a solução mais simples é a que sobrevive.
“rqlite é um banco de dados relacional tolerante a falhas que você pode rodar por conta própria, entender completamente, e não pagar ninguém pra usar.” (Philip O’Toole)
Se você está construindo algo que precisa de banco de dados relacional com alta disponibilidade e não quer (ou não pode) rodar PostgreSQL, dá uma chance pro SQLite distribuído. Depois de 12 anos, acho que ele já provou que funciona.
Fonte de inspiração: Twelve years of distributed SQLite













