Sviluppo web

SQLite vs Postgres su un progetto piccolo

Un progetto piccolo con un solo processo applicativo sta in SQLite con WAL: 300.000 righe occupano 26,8 MB e le letture indicizzate restano sotto 0,1 ms. Postgres vince con più scrittori.

In sintesi

  • Con un solo processo applicativo e pochi scrittori, SQLite in modalità WAL copre il caso senza un servizio da gestire.
  • 300.000 righe occupano 26,8 MB e la lettura indicizzata misura 0,024 ms di mediana contro 15,471 ms senza indice.
  • Il limite non è la dimensione: è la concorrenza in scrittura, perché un solo writer per volta può procedere.

Per un progetto piccolo con un solo processo applicativo, SQLite in modalità WAL basta: 300.000 righe occupano 26,8 MB e le letture indicizzate restano sotto un decimo di millisecondo. PostgreSQL conviene quando servono scrittori concorrenti, client in rete o estensioni che SQLite non ha.

Cosa ottieni

  • Un file: il database è un file sul disco dell'applicazione, senza servizio, porta o credenziale da configurare.
  • Backup in una riga: il comando .backup legge uno stato consistente anche con il sito in funzione.
  • Transazioni ACID: le garanzie su atomicità e isolamento ci sono, con BEGIN IMMEDIATE per prendere il lock di scrittura subito.
  • Una licenza che non chiede nulla: pubblico dominio, nessun obbligo di attribuzione o di apertura del codice.

Cosa perdi

  • Scrittori concorrenti: uno solo alla volta scrive; gli altri aspettano il lock, e senza busy_timeout ricevono un errore invece di attendere.
  • Più host: il file sta su un disco locale. Su un filesystem di rete il locking non è affidabile, quindi due server non condividono lo stesso database.
  • Estensioni e repliche: niente PostGIS, nessuna replica in lettura nativa, nessun parallel query.
  • Ruoli e permessi: i permessi sono quelli del filesystem, non dell'utente del database.

I numeri del test

MisuraValore
Righe nella tabella300.000
Insert in una transazione299 ms
File del database26,8 MB
File WAL della sessione14,6 MB
Lettura indicizzata, mediana0,024 ms
Lettura senza indice, mediana15,471 ms
5.000 insert senza indici5 ms
5.000 insert con tre indici85 ms
VersioneSQLite 3.51.3, Node 24.15.0

Quando conviene migrare

Il segnale non è la dimensione del database, è il numero di processi che scrivono. Due istanze dell'applicazione dietro un load balancer violano già il modello a scrittore singolo, e un jobs worker che scrive mentre il sito scrive crea attese che nessun indice risolve. Aggiungi a questo la richiesta di repliche in lettura, di backup point-in-time o di un'estensione geografica e la migrazione si paga da sola.

Modalità, backup, attese

Tre impostazioni fanno la differenza in produzione: WAL per non bloccare le letture durante una scrittura, un busy_timeout perché le attese diventino attese invece di errori, e il backup con .backup invece della copia del file. Le stesse impostazioni rendono il passaggio a PostgreSQL più semplice, perché la logica applicativa non dipende dal motore.

sqlite3 app.db "PRAGMA journal_mode=WAL; PRAGMA busy_timeout=5000;"
sqlite3 app.db ".backup 'backup.db'"
sqlite3 app.db "PRAGMA integrity_check;"

Il backup online lascia intatti i file -wal e -shm del database in uso: sono parte dello stato, non rifiuti. Se copi il database a mano mentre l'applicazione scrive, il rischio è un file che apre senza errori ma con pagine incoerenti, e il controllo di integrità è l'unico modo per accorgersene.

Il catalogo EneUI

Una vista sulle righe serve comunque, qualunque sia il motore: in catalogo ci sono i componenti tabella, i blocchi dashboard e il record table di Origin UI, licenza MIT dichiarata a monte. Controllo eseguito il 1 novembre 2026 sul catalogo da 111.985 componenti.

La limitazione

I numeri vengono da una macchina sola, con Node e un disco locale di cui non conosciamo le prestazioni: non sono un confronto fra motori. Non abbiamo misurato il comportamento con più scrittori simultanei né la latenza su un filesystem di rete, che è proprio il caso in cui SQLite peggiora. Se il deploy è serverless, multi-regione o su più container che scrivono, la risposta è PostgreSQL e non c'è misura che la cambi.

Dove continuare

La forma delle query e del contratto è in progettare un'API; le regole di cache che decidono metà della latenza percepita sono in header di cache HTTP. Se stai scegliendo fra stili di API, il confronto con i costi di entrambi è in MCP e REST.

Domande frequenti

SQLite regge un sito in produzione?

Sì, con un solo processo applicativo e un traffico in scrittura moderato. Il limite è la concorrenza: un writer per volta, gli altri attendono o ricevono SQLITE_BUSY.

Quanti dati posso mettere in SQLite?

Il limite teorico è di 281 TB per database, quindi non è la dimensione a decidere. Decidono il numero di scrittori simultanei e la necessità di accesso da più host.

Meglio WAL o journal di default?

WAL in produzione: permette letture mentre una scrittura è in corso e riduce le attese. Introduce i file -wal e -shm, che vanno inclusi nel backup.

Come faccio il backup senza fermare il sito?

Con il comando .backup, che usa l'API di backup online e legge uno stato consistente. Copiare il file con cp mentre si scrive può produrre un backup corrotto.

Quando è ora di passare a PostgreSQL?

Con più processi applicativi, scritture da servizi diversi, richiesta di repliche in lettura o estensioni. A quel punto il costo di migrazione è più basso del costo di restare.