SQLite Full-Text Search: The Hidden Search Engine Inside Your Database
Need to add search to your app? Most developers immediately reach for Elasticsearch, Algolia, or Meilisearch. But if you're already using SQLite, you might not need any of that.
SQLite has a built-in full-text search engine called FTS5. It's been around since 2015, it's fast, it requires zero external dependencies, and it's surprisingly capable. You get relevance ranking, phrase searches, boolean operators, and even result highlighting - all from a few SQL statements.
Let's build a searchable knowledge base to see how it works.
Creating an FTS5 Table
FTS5 uses virtual tables. Instead of CREATE TABLE, you use CREATE VIRTUAL TABLE ... USING fts5():
That's it. We now have a searchable knowledge base with 6 articles. The FTS5 engine automatically tokenizes and indexes all the text.
Basic Searching with MATCH
To search an FTS5 table, use the MATCH operator:
Multiple search terms are implicitly ANDed together:
Search Operators & Syntax
FTS5 supports powerful query syntax for precise searches.
Phrase Searches
Use double quotes to match exact phrases:
Boolean Operators
Use OR for alternatives, NOT to exclude:
Prefix Searches
Use * to match word prefixes:
Column Filters
Search within a specific column:
Ranking Results with bm25()
By default, FTS5 returns results in arbitrary order. Use bm25() to rank by relevance:
The bm25() function implements the Okapi BM25 ranking algorithm - the same algorithm used by search engines like Elasticsearch. Lower (more negative) scores mean higher relevance.
You can also weight columns differently. For example, matches in the title might be more important than matches in the content:
Highlighting & Snippets
When building a search UI, you want to show users where their search terms matched. FTS5 has built-in functions for this.
highlight()
The highlight() function wraps matching terms in tags:
The arguments are: table name, column index (0-based), opening tag, closing tag. You can use any HTML or markers you want.
snippet()
The snippet() function extracts a portion of text around the match - perfect for search result previews:
The snippet() arguments are: table, column index, opening tag, closing tag, ellipsis text, and max tokens to include.
Using FTS5 with Existing Tables
So far we've stored content directly in the FTS5 table. But what if you already have a regular table and want to add search?
FTS5 supports external content tables - the FTS index references data stored elsewhere:
The content= option tells FTS5 where the actual data lives. You'll need to keep the FTS index in sync when data changes - typically using triggers:
For many use cases, storing data directly in the FTS5 table is simpler. Use external content tables when you need the relational features of regular tables (foreign keys, additional columns, etc.).
Wrapping Up
SQLite's FTS5 is a legitimate full-text search engine hiding inside your database. You can:
- Create searchable tables with
CREATE VIRTUAL TABLE ... USING fts5() - Search with MATCH using terms, phrases, boolean operators, and prefixes
- Rank by relevance with the
bm25()function - Highlight matches and extract snippets for your UI
- Index existing tables using external content mode
For many applications - especially desktop apps, mobile apps, and smaller web services - FTS5 is all the search engine you need. No external dependencies, no separate service to manage, just SQL.
Check out my other SQLite posts on JSON virtual columns and JSON functions if you want to keep exploring what SQLite can do.
Thanks for reading!
Jay