Introduction
SQLite is often underestimated for production environments. However, with the right configurations and advanced techniques, it can handle millions of records with latency under 1 ms. This tutorial guides you through real optimization: enabling WAL mode, creating smart composite indexes, using FTS5 for full-text search, and precise PRAGMA tuning. Each section includes directly usable code.
Prerequisites
- SQLite 3.42+
- Solid knowledge of SQL and indexing
- Node.js 20+ with better-sqlite3
- Access to a terminal and code editor
Enable WAL Mode
PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;
PRAGMA wal_autocheckpoint = 1000;WAL mode enables concurrent reads without locking. synchronous=NORMAL offers the best performance/security compromise. Automatic checkpointing prevents the WAL file from growing indefinitely.
Create Composite Indexes
CREATE INDEX idx_orders_customer_date
ON orders(customer_id, created_at DESC)
WHERE status = 'completed';A composite index covering the most filtered and sorted columns avoids full scans. The partial WHERE clause reduces index size and improves performance for common queries.
Configure Critical PRAGMA
PRAGMA cache_size = -64000;
PRAGMA temp_store = MEMORY;
PRAGMA mmap_size = 30000000000;A 64 MB cache in negative notation, temporary storage in memory, and 30 GB mmap allow SQLite to fully utilize available RAM without disk overhead.
Implement FTS5
CREATE VIRTUAL TABLE documents_fts
USING fts5(title, content, tokenize='porter unicode61');FTS5 with porter and unicode61 tokenizer provides performant and relevant full-text search. It automatically handles word inflection and special characters.
Optimized Query with FTS5
SELECT d.id, d.title, rank
FROM documents d
JOIN documents_fts ON d.id = documents_fts.rowid
WHERE documents_fts MATCH 'optimisation production'
ORDER BY rank;Joining with documents_fts and using rank enables relevance-based sorting. SQLite uses the FTS5 index to avoid any table scans.
Best Practices
- Always enable WAL and verify regular checkpointing
- Create partial indexes only on active data
- Use explicit transactions for batch operations
- Monitor WAL and journal file sizes
- Run VACUUM after large deletions
Common Mistakes to Avoid
- Forgetting to switch to WAL before loading data
- Creating too many indexes without testing real queries
- Ignoring cache_size and mmap_size PRAGMA settings
- Not setting size limits for WAL files
Going Further
Deepen these concepts with our expert training on embedded databases. Discover our Learni training.