Chapter 19 · Security, Deployment, Reliability Boundaries, and When Not to Use SQLite
When SQLite Is the Right Database — and When to Move to PostgreSQL / MySQL / DuckDB / etc.
Use workload and operational requirements—not folklore about row counts—to decide when SQLite is an excellent fit, when another embedded analytical engine fits better, and when a client/server database is the safer architecture.
Learning outcomes
“Can SQLite hold this many rows?” is rarely the right architecture question. The more important questions are where the data lives relative to the application, how many writers need to make progress simultaneously, who must authenticate/authorize clients, what availability/replication model is required, and whether the dominant workload is transactional point access or analytical scanning. This final architecture lesson turns those requirements into migration triggers.
Use SQLite’s official appropriate-use guidance as a baseline rather than arbitrary file-size or row-count myths.
Identify strong-fit SQLite workloads: local/embedded state, application file formats, edge/mobile, caches, tests, and suitable services.
Recognize server-oriented requirements such as many concurrent writers, remote direct clients, centralized authorization, HA/replication, and multi-service ownership.
Distinguish embedded transactional SQLite from analytical embedded systems such as DuckDB.
Define migration triggers as measurable requirements/metrics instead of “the database reached X GB.”
Complete five architecture scenarios and defend the database choice with operational evidence.
SQLite solves a different problem from a database server
SQLite runs in the application process and reads/writes its local database file. PostgreSQL/MySQL-class systems run a server that owns database files and accepts client connections. SQLite’s official guidance emphasizes local storage simplicity and reliability; client/server systems emphasize centralized coordination, authorization, and higher write concurrency. Neither architecture is universally superior.
| Question | SQLite direction | Client/server direction |
|---|---|---|
| Where does SQL execute? | Inside each application process using SQLite library. | On database server on behalf of clients. |
| Where should DB file live? | Normally same device/host as SQLite-using application/service. | Files stay private to server; clients connect via protocol. |
| Writers | One writer at an instant per DB file; short writes can queue effectively. | Designed to coordinate many concurrent client transactions. |
| Authorization boundary | OS/file + application-owned authorization. | Server accounts/roles/policies can form a central boundary. |
| Operations | Single-file/local lifecycle, application-owned backup/migration. | Server administration, connection management, replication/HA ecosystems. |
| Best fit | Embedded/local application data and suitable low/moderate-write services. | Shared centralized data, many writers/clients, HA/governance requirements. |
Strong-fit SQLite cases
SQLite is particularly compelling when keeping the engine with the application removes operational machinery rather than creating a concurrency bottleneck.
| Use case | Why SQLite fits |
|---|---|
| Desktop/mobile application state | Local, offline-capable, transactionally consistent single-file data. |
| Edge/IoT device | No server dependency; small footprint; robust local transactions. |
| Application document/file format | Structured, queryable, versionable file with atomic updates. |
| Cache / synchronized local subset | Local reads continue during network outage; central system remains source of truth. |
| Tests / demos / development fixtures | Easy isolated files and reproducible schemas without provisioning a server. |
| Small/moderate web/API service with short writes | Can be excellent when one service host owns local DB and write demand fits single-writer behavior. |
| Local metadata/catalog/configuration | Simple deployment with strong transactional semantics. |
SQLite’s appropriate-use page contains historical traffic examples, but request count alone does not determine fit. A read-heavy service and a write-heavy service with the same request count can have completely different database pressure. Measure transaction concurrency, write duration, working set, latency, and availability requirements.
Warning case 1: many concurrent writers
SQLite can queue writers and often handles more write activity than teams expect when transactions are short. The migration signal is not “two writers exist”; it is that the required concurrent write throughput/latency cannot be met with short transactions, sensible batching, busy handling, and a topology that keeps the file local.
Record over representative peak windows: writes/sec and commits/sec p50/p95/p99 write transaction duration SQLITE_BUSY rate and total retry wait writer queue/backlog age WAL checkpoint behavior CPU + storage latency transaction batch size percent of time writer slot is occupiedMigration trigger example: "p99 durable write latency > 250 ms for 15 min while writer occupancy > 85% after documented query/batch fixes"# Replace thresholds with your product SLOs; these are an example shape.
Warning case 2: direct network clients and server authorization
If many machines need to query the same authoritative data directly, a client/server database normally places the engine next to the data and lets clients send compact SQL/protocol messages. If the product also needs central roles, credential rotation, connection admission, auditing, row/tenant authorization, or DB-level network policies, a server system may be the natural security boundary rather than trying to recreate it around a shared SQLite file.
Warning case 3: HA, replicas, failover, and multi-service ownership
SQLite does not include a built-in distributed consensus/replication service or automatic multi-node failover system in core. Products can build replication around SQLite, and specialized SQLite-based systems exist, but that becomes an additional architecture with its own consistency/failure semantics. If the core product requirement is a centrally operated, multi-node transactional database with standard replication/failover tooling, evaluate a client/server system directly.
| Requirement | Question to ask |
|---|---|
| Automatic failover | Who detects failure, elects a writer, fences the old writer, and proves no split-brain writes? |
| Read replicas | What consistency/staleness is acceptable and how are replicas produced? |
| Point-in-time recovery | What log/history mechanism exists and who operates it? |
| Multi-service writes | Who owns schema/migrations and cross-service transaction semantics? |
| Online maintenance | Can required backup/upgrade/reindex operations meet service availability SLOs? |
SQLite versus DuckDB: embedded does not mean same workload
DuckDB also emphasizes in-process simplicity, but its official design targets analytical/OLAP workloads with vectorized execution and column-oriented analytical behavior. SQLite is primarily a transactional/general-purpose embedded relational database with row-oriented B-tree storage. A product may even use both: SQLite for application state and DuckDB for local analytical scans over large columnar files/data extracts.
| Workload | SQLite | DuckDB / analytical direction |
|---|---|---|
| Frequent small inserts/updates + point lookups | Natural SQLite strength. | Not the primary design target. |
| Application settings/state/transactions | Natural SQLite strength. | Usually unnecessary. |
| Large scans, aggregations, Parquet analytics | Possible, but row-oriented design may not be ideal. | Core analytical target. |
| Many concurrent remote OLTP writers | Consider client/server DB, not DuckDB as a drop-in OLTP server. | DuckDB is not simply “PostgreSQL but embedded.” |
| Local notebook/data-science analytics | SQLite can work for smaller relational datasets. | DuckDB often better aligned with OLAP/file analytics. |
Migration is a system project, not a file conversion
Moving from SQLite to PostgreSQL/MySQL/etc. changes transaction/concurrency behavior, type semantics, SQL dialect details, connection failures, authentication, migrations, deployment, backups, monitoring, and operational ownership. Do not migrate solely because a database file “feels large.” Build a requirements-driven plan and run representative workload tests on the target.
Trigger category Evidence / threshold Status--------------------------- ----------------------------- ------Concurrent writer SLO _____________________________ _____Remote direct client need _____________________________ _____DB-server authorization _____________________________ _____Multi-node HA/RTO/RPO _____________________________ _____Central multi-service writes _____________________________ _____Dataset/storage management _____________________________ _____Analytical scan workload _____________________________ _____Operational staffing/tools _____________________________ _____Regulatory/audit controls _____________________________ _____Decision: keep SQLite / complement it / migrateOwner: _____________________ Review date: _______________
Five architecture review scenarios
| Scenario | Recommended direction | Reasoning |
|---|---|---|
| A. Offline maintenance-tablet app; one user; 2 GB local history; syncs when online. | SQLite | Local/offline state, modest writer concurrency, simple device deployment. File size alone is not a reason to leave. |
| B. SaaS billing core; 40 application replicas; many simultaneous account updates; central roles/audit; multi-AZ failover required. | PostgreSQL/MySQL-class client/server DB | Concurrent writes, centralized authorization, multi-node HA and shared authoritative data are server-oriented requirements. |
| C. Desktop CAD app stores project graph, settings, and thumbnails in one portable file. | SQLite | Application file-format use case with atomic structured updates and easy portability. |
| D. Data analyst scans hundreds of GB of Parquet locally for joins/aggregations; little row-by-row OLTP. | DuckDB/analytical engine | Dominant workload is embedded OLAP over columnar files, not transactional application state. |
| E. One regional API server on local NVMe; mostly reads; short queued writes; daily backup; no HA requirement yet. | SQLite, with measured review triggers | One service host owns the file and current requirements may fit well. Instrument writer saturation and availability needs before premature migration. |
Production architecture checklist
[ ] SQLite engine and DB file are on the same appropriate host/filesystem.[ ] Required peak write concurrency fits one-writer-at-a-time behavior.[ ] Busy/retry metrics show bounded, understood contention.[ ] Application, not SQLite roles, owns end-user authorization.[ ] OS file/directory/backup permissions match least privilege.[ ] Encryption need (if any) has an explicit product/key-management design.[ ] trusted_schema/defensive/extension policies match the threat model.[ ] Backups and restore drills satisfy RPO/RTO.[ ] HA/replication requirements are either absent or explicitly engineered.[ ] Runtime SQLite version/build is patched and capability-tested.[ ] Dataset growth fits operational storage/backup/maintenance, not a folklore threshold.[ ] Analytical workloads are evaluated separately from OLTP state.[ ] Migration triggers are measurable and owned, not emotional guesses.
Chapter synthesis
Choose architecture from requirements
Defend each answer.
- Why is a 50 GB SQLite database not automatically a reason to migrate?
- What is a stronger migration signal than raw row count?
- Why does a centralized role/HA requirement point toward a server database even if SQLite queries are fast?
- When might DuckDB complement SQLite rather than replace it?
- Why is moving the SQLite file to a network share usually not the same as “scaling out”?
- What must be true before declaring SQLite the wrong database?
Review the answers
Operational fit depends on access pattern, storage, backup, writer concurrency and SLOs, not one size number. Sustained writer saturation/latency, remote direct clients, centralized authorization, HA or multi-service ownership are stronger architectural signals. DuckDB can handle analytical scans while SQLite retains transactional application state. A network share inserts the network into SQLite’s file-I/O/locking path rather than adding a coordinating server. Declare SQLite wrong only after requirements/evidence show that its architecture cannot meet the needed guarantees economically or safely.
Bridge to the production capstone
Chapter 20 now asks you to apply the whole course. You will define FieldNotes requirements and workload, defend SQLite fit, implement schema and migrations, build safe application access and concurrency handling, test/benchmark/backup/secure the database, and finish with an operational architecture that can explain both what SQLite guarantees and what the surrounding system must guarantee.