Schema
How it fits together
codebasesregisters each project root. A single database can index multiple codebases.chunksstores individual semantic units extracted from source files — functions, structs, classes, impl blocks, etc. Each chunk has aname,signature, codesnippet, line range, and optionally a vectorembedding. Thechunk_keyis a unique identifier (e.g.file_path::kind::name) for upsert operations.indexed_filestracks which files have been indexed and their content hashes, enabling incremental re-indexing — only changed files are re-processed.
Connecting
The FTS index features require an experimental flag at connection time:The
experimental: ["index_method"] flag enables Turso’s USING fts index syntax and the fts_match() / fts_score() functions.Indexing files
Upserting chunks
When a file is parsed, upsert its chunks. Settingembedding = NULL on conflict forces re-embedding when content changes:
Tracking indexed files
Skipping unchanged files
Before parsing a file, check if it has changed:Storing embeddings
Embeddings can be stored as int8-quantized vectors using Turso’svector8() function, which reduces storage from 1,536 bytes (float32, 384 dims) to 395 bytes:
vector8() is a JSON-stringified float array. Turso handles the quantization internally.
Find chunks that need embedding:
Full-text search
Turso provides an FTS index with weighted BM25 scoring that is separate from SQLite’sfts5 virtual tables.
Creating the FTS index
Create an FTS table per codebase and populate it from the chunks:weights parameter controls BM25 scoring — here, matches in the function/type name are weighted 5x and signature matches 3x.
Searching with FTS
Vector search
For semantic/natural language queries, use vector cosine distance:1 - distance (cosine similarity from cosine distance).
Hybrid search
For the best results, combine both approaches using Reciprocal Rank Fusion (RRF). Run the FTS and vector queries separately, then merge results in application code:Removing stale files
When files are deleted from the codebase, clean up their chunks and records:Key design points
- Incremental indexing via file hashes means only changed files are re-parsed and re-embedded, making updates fast even on large codebases.
- Two search modes — FTS for identifier/keyword lookup and vector search for semantic/natural language queries — cover different use cases. Hybrid search combines both.
- Weighted FTS (
name=5.0, signature=3.0) biases results toward function and type names, which is what developers usually search for. - Int8 quantized vectors via
vector8()reduce storage by 75% compared to float32 with minimal impact on search quality. - Everything runs in a single embedded database file with no external services.