1. What SQLite actually is
Every database you've likely heard of before this — Postgres, MySQL, SQL Server — is a client-server system: a separate process (the database server) runs somewhere, listens on a network port, and your app connects to it as a client, even if that server is running on the same machine.
SQLite throws that model away. There is no server process. The "database" is just a single file on disk (commonly ending in .db or .sqlite), and SQLite is a C library that gets linked directly into whatever program wants to read or write that file. When your app calls a SQL query, it isn't talking to another process over a socket — it's calling a function in its own process that reads and writes the file directly.
It still speaks real SQL (most of the standard: SELECT, JOIN, transactions, indexes, foreign keys) and is fully ACID-compliant. It's not a toy or a "lite" subset of relational features — the name refers to the lightweight, embedded nature of the engine, not a lightweight feature set.
2. Why it exists — and why "serverless database" is the right way to think about it
SQLite was built for the case where running and maintaining a separate database server is pure overhead: no process to start, no port to expose, no credentials to manage, no network round-trip for every query. It is, by shipped volume, probably the most widely deployed database engine in the world — it's embedded in every major web browser, most mobile operating systems, and countless desktop apps, usually invisibly.
The mental shift worth making: SQLite isn't "a smaller Postgres." It's a different category of tool — an embedded storage engine that happens to expose itself through SQL, aimed at a single application owning a file, not multiple applications sharing a service.
3. What it's genuinely good at
- Zero setup. No install, no server to configure, no connection string beyond a file path. A prototype can have real SQL and real transactions in the time it takes to write one line of code.
- Portability. The entire database is one file. Back it up by copying it. Ship it inside a mobile app bundle. Attach it to a bug report.
- Speed for single-process workloads. No network hop, no serialization over a socket — for an app that owns its data and doesn't need to share it, SQLite can outperform a network-bound server database.
- Reliability at small-to-medium scale. It's one of the most tested pieces of software in existence, with an enormous automated test suite; the file format itself is stable enough that the SQLite project guarantees long-term backward compatibility.
- Great for read-heavy, single-writer workloads — content sites, local caches, config storage, analytics snapshots, edge/CDN deployments where each region gets its own read replica of a file.
4. Where it breaks down
- No built-in networking. If two different servers (two separate machines) need to read and write the same data, SQLite has no answer — the file lives on one disk. You'd need a shared filesystem hack or a completely different tool.
- Limited to one host's disk. It doesn't horizontally scale the way a managed cloud database does. Growth beyond a single machine's storage and I/O ceiling means migrating away.
- No user/permission system. Anyone with file access to the
.db file has full access — there's no login, no per-user grants like a server database has. Access control has to happen at the application or OS-file level instead.
- Weaker for heavy concurrent writes. Covered in depth below — this is the single biggest reason teams outgrow it.
5. The concurrency question, in detail
This is the part that actually matters in production decisions, so it's worth being precise instead of just saying "SQLite can't handle concurrency" (which overstates the problem).
SQLite supports unlimited simultaneous readers. Where it differs from a server database is on writes: by default, only one write transaction can be in progress at any instant. If a second write comes in while the first is running, it queues and waits — it doesn't fail outright, but it does block.
In practice, this matters less than it sounds: writes in most apps are quick (a few milliseconds), so a queue of writers rarely becomes a bottleneck for low-to-moderate traffic. SQLite also ships a Write-Ahead Log (WAL) mode, which lets reads keep happening concurrently with an in-progress write and generally improves throughput over the older rollback-journal mode — most modern SQLite deployments (including popular tools like PocketBase) run in WAL mode by default for exactly this reason.
Where it actually breaks: a genuinely high write-concurrency workload — many independent processes or many parallel requests all writing at once, sustained — will start queuing noticeably and become a real bottleneck. That's the point where "just use SQLite" stops being obviously true. Newer projects like Turso have specifically tried to relax the single-writer limitation, which itself is a signal of how real the limitation is in practice.
6. How it compares to a "real" server database
| Dimension | SQLite | Postgres / MySQL (server) |
| Deployment | Embedded, single file, no server process | Separate server process, network protocol |
| Concurrent writers | One at a time (queued) | Many, handled by the engine's concurrency control |
| Multi-machine access | Not supported natively | Core use case — many app servers, one database |
| Setup cost | Effectively zero | Requires provisioning, credentials, networking |
| User/permission system | None — file-level only | Full role-based access control |
| Best fit | Single app owning its data, embedded/local/edge use | Multiple clients or services sharing one dataset |
7. A practical example
Picture a small internal tool: a single Node.js or Python process serving a handful of teammates a dashboard, backed by a few thousand rows of data that update occasionally. SQLite is a strong default here — one file, no infrastructure, trivial backups (copy the file), and the write load is low enough that the single-writer limitation never surfaces.
Now picture the same dashboard, but it grows into a multi-region SaaS product with dozens of backend instances all writing to the same dataset simultaneously, and a requirement that any instance, anywhere, can read the latest write immediately. That's the point SQLite was never designed for — the correct move is a managed server database (or one of the newer "SQLite-compatible but networked" services covered in the next lesson).
8. The rule of thumb
Use SQLite when one process (or a small number of processes on one machine) owns the data, write volume is light-to-moderate, and you want zero infrastructure. Move to a server database when multiple machines need to write concurrently, you need real user-level permissions, or sustained write concurrency starts queuing noticeably.
The official SQLite documentation puts it plainly: it's a great fit for embedded devices, local caches, prototypes, and the "device/edge" side of computing — and a poor fit for anything that looks like a shared, multi-writer client-server workload at real scale. Next lesson covers the alternatives that pick up exactly where that line gets crossed: Postgres, MySQL, Turso, and PlanetScale.
1. O que o SQLite realmente é
Todo banco de dados que você provavelmente já ouviu falar antes deste — Postgres, MySQL, SQL Server — é um sistema cliente-servidor: um processo separado (o servidor do banco) roda em algum lugar, escuta numa porta de rede, e sua aplicação se conecta a ele como cliente, mesmo que esse servidor rode na mesma máquina.
O SQLite descarta esse modelo. Não existe processo de servidor. O "banco de dados" é só um arquivo único em disco (geralmente terminando em .db ou .sqlite), e o SQLite é uma biblioteca em C que é linkada direto no programa que quer ler ou escrever esse arquivo. Quando sua aplicação faz uma query SQL, ela não está falando com outro processo por um socket — está chamando uma função no próprio processo dela que lê e escreve o arquivo diretamente.
Ainda assim ele fala SQL de verdade (a maior parte do padrão: SELECT, JOIN, transações, índices, foreign keys) e é totalmente ACID. Não é um brinquedo nem um subconjunto "lite" de recursos relacionais — o nome se refere à natureza leve e embarcada do motor, não a um conjunto reduzido de funcionalidades.
2. Por que ele existe — e por que "banco serverless" é a forma certa de pensar nele
O SQLite foi construído pro caso em que rodar e manter um servidor de banco separado é pura sobrecarga: nenhum processo pra iniciar, nenhuma porta pra expor, nenhuma credencial pra gerenciar, nenhuma ida-e-volta de rede pra cada query. É, em volume de instalações, provavelmente o motor de banco de dados mais distribuído do mundo — está embarcado em todo navegador web importante, na maioria dos sistemas operacionais mobile, e em inúmeros apps desktop, geralmente de forma invisível.
A mudança de mentalidade que vale a pena fazer: o SQLite não é "um Postgres menor". É uma categoria diferente de ferramenta — um motor de armazenamento embarcado que por acaso se expõe via SQL, voltado a uma única aplicação que é dona de um arquivo, não a múltiplas aplicações compartilhando um serviço.
3. No que ele é genuinamente bom
- Configuração zero. Sem instalação, sem servidor pra configurar, sem connection string além de um caminho de arquivo. Um prototipo pode ter SQL de verdade e transações de verdade no tempo que leva pra escrever uma linha de código.
- Portabilidade. O banco inteiro é um arquivo só. Faça backup copiando o arquivo. Empacote dentro de um app mobile. Anexe a um bug report.
- Velocidade pra cargas de trabalho de processo único. Sem salto de rede, sem serialização por socket — pra uma aplicação dona dos próprios dados e que não precisa compartilhá-los, o SQLite pode superar um banco de servidor limitado pela rede.
- Confiabilidade em escala pequena a média. É um dos softwares mais testados que existem, com uma suíte de testes automatizados enorme; o próprio formato de arquivo é estável o suficiente pra que o projeto SQLite garanta compatibilidade retroativa de longo prazo.
- Ótimo pra cargas com muita leitura e um só escritor — sites de conteúdo, cache local, armazenamento de config, snapshots de analytics, deploys edge/CDN onde cada região tem sua própria réplica de leitura de um arquivo.
4. Onde ele quebra
- Sem rede embutida. Se dois servidores diferentes (duas máquinas separadas) precisam ler e escrever os mesmos dados, o SQLite não tem resposta — o arquivo vive num disco só. Você precisaria de um sistema de arquivos compartilhado (gambiarra) ou de uma ferramenta completamente diferente.
- Limitado ao disco de uma máquina. Ele não escala horizontalmente como um banco de nuvem gerenciado. Crescer além do teto de armazenamento e I/O de uma única máquina significa migrar pra outra coisa.
- Sem sistema de usuários/permissões. Qualquer um com acesso ao arquivo
.db tem acesso total — não existe login, não existem grants por usuário como num banco de servidor. Controle de acesso precisa acontecer no nível da aplicação ou do arquivo do sistema operacional.
- Mais fraco pra muita escrita concorrente. Detalhado abaixo — é o maior motivo pelo qual times acabam saindo dele.
5. A questão da concorrência, em detalhe
Essa é a parte que realmente importa em decisões de produção, então vale ser preciso em vez de só dizer "SQLite não lida com concorrência" (o que exagera o problema).
O SQLite suporta leitores simultâneos ilimitados. Onde ele difere de um banco de servidor é na escrita: por padrão, só uma transação de escrita pode estar em andamento a cada instante. Se uma segunda escrita chega enquanto a primeira está rodando, ela entra na fila e espera — não falha de imediato, mas bloqueia.
Na prática, isso importa menos do que parece: escritas na maioria das aplicações são rápidas (poucos milissegundos), então uma fila de escritores raramente se torna um gargalo pra tráfego baixo a moderado. O SQLite também traz um modo Write-Ahead Log (WAL), que permite que leituras continuem acontecendo em paralelo com uma escrita em andamento e geralmente melhora a vazão em relação ao modo mais antigo de rollback journal — a maioria dos deploys modernos de SQLite (incluindo ferramentas populares como o PocketBase) roda em modo WAL por padrão exatamente por isso.
Onde ele realmente quebra: uma carga de trabalho com concorrência de escrita genuinamente alta — muitos processos independentes ou muitas requisições paralelas escrevendo ao mesmo tempo, de forma sustentada — vai começar a filar visivelmente e se tornar um gargalo real. É o ponto em que "só usa SQLite" deixa de ser obviamente verdade. Projetos mais novos como o Turso tentaram especificamente relaxar a limitação de escritor único, o que por si só é um sinal de quão real essa limitação é na prática.
6. Como ele se compara a um banco de servidor "de verdade"
| Dimensão | SQLite | Postgres / MySQL (servidor) |
| Deploy | Embarcado, arquivo único, sem processo de servidor | Processo de servidor separado, protocolo de rede |
| Escritores concorrentes | Um por vez (em fila) | Muitos, controlados pelo mecanismo de concorrência do motor |
| Acesso multi-máquina | Não suportado nativamente | Caso de uso central — muitos servidores de app, um banco |
| Custo de configuração | Praticamente zero | Exige provisionamento, credenciais, rede |
| Sistema de usuários/permissões | Nenhum — só nível de arquivo | Controle de acesso completo baseado em papéis |
| Melhor uso | Uma aplicação dona dos próprios dados, uso embarcado/local/edge | Múltiplos clientes ou serviços compartilhando um conjunto de dados |
7. Um exemplo prático
Imagine uma ferramenta interna pequena: um único processo Node.js ou Python servindo um dashboard pra um punhado de colegas, com uns poucos milhares de linhas de dados que mudam ocasionalmente. O SQLite é uma escolha forte aqui — um arquivo só, sem infraestrutura, backup trivial (copiar o arquivo), e a carga de escrita é baixa o suficiente pra que a limitação de escritor único nunca apareça.
Agora imagine o mesmo dashboard, mas ele cresce pra um produto SaaS multi-região com dezenas de instâncias de backend todas escrevendo no mesmo conjunto de dados simultaneamente, e um requisito de que qualquer instância, em qualquer lugar, consiga ler a última escrita imediatamente. Esse é o ponto pro qual o SQLite nunca foi desenhado — a decisão certa é um banco de servidor gerenciado (ou um dos serviços mais novos "compatíveis com SQLite mas em rede" cobertos na próxima lição).
8. A regra prática
Use SQLite quando um processo (ou um número pequeno de processos numa única máquina) é dono dos dados, o volume de escrita é leve a moderado, e você quer infraestrutura zero. Migre pra um banco de servidor quando múltiplas máquinas precisam escrever concorrentemente, você precisa de permissões reais por usuário, ou a concorrência de escrita sustentada começa a filar visivelmente.
A documentação oficial do SQLite coloca isso de forma direta: é uma ótima escolha pra dispositivos embarcados, cache local, prototipagem, e o lado "dispositivo/edge" da computação — e uma escolha ruim pra qualquer coisa que se pareça com uma carga de trabalho cliente-servidor compartilhada, com múltiplos escritores, em escala real. A próxima lição cobre as alternativas que assumem exatamente a partir desse ponto: Postgres, MySQL, Turso e PlanetScale.