# How to Integrate OmniRoute's Memory System with FTS5 and Vector Quantization

> Learn how to integrate OmniRoute's memory system with FTS5 and vector quantization for fast hybrid retrieval. Optimize your search with textual and semantic queries.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-07-19

---

**OmniRoute combines SQLite FTS5 virtual tables for full-text search and scalable vector quantization to store compressed embeddings, enabling fast hybrid retrieval across textual and semantic queries.**

The open-source OmniRoute repository (`diegosouzapw/OmniRoute`) provides a conversational memory layer that stores "memories" in SQLite and optionally off-loads vectors to Qdrant. By integrating **FTS5** for keyword search and **vector quantization** for efficient embedding storage, you can significantly improve retrieval speed while reducing disk usage.

## Understanding OmniRoute's Dual Retrieval Architecture

OmniRoute maintains conversational context through two complementary indexing strategies: lexical search via FTS5 and semantic search via vector stores. These systems operate independently but can be queried together for hybrid retrieval.

### Full-Text Search with FTS5

The memory system uses SQLite's native **FTS5** extension to create a virtual table mapped to the `memories` table. This is implemented in migration [`022_add_memory_fts5.sql`](https://github.com/diegosouzapw/OmniRoute/blob/main/022_add_memory_fts5.sql), which creates the `memories_fts` virtual table and indexes the `content` column.

When enabled, textual insertions automatically populate both the base `memories` table and the FTS5 index, allowing you to run high-performance `MATCH` queries without scanning full table rows.

### Vector Storage Options

OmniRoute supports three storage backends controlled by the `memoryVectorStore` setting in [`src/lib/memory/settings.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/memory/settings.ts):

- **`"sqlite-vec"`** (default): Embeddings stored in SQLite using the `sqlite-vec` extension
- **`"qdrant"`**: Off-loads vectors to an external Qdrant collection
- **`"auto"`**: Currently defaults to SQLite

The active configuration is persisted via [`src/lib/db/memoryVec.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/memoryVec.ts) and can be modified through the Settings API or CLI.

## Configuring FTS5 for Memory Content

To enable full-text search capabilities, you must apply the FTS5 migration. This creates the virtual table that shadows your existing memories.

Run the migration using the provided npm script:

```bash
npm run migration:run

```

This executes [`022_add_memory_fts5.sql`](https://github.com/diegosouzapw/OmniRoute/blob/main/022_add_memory_fts5.sql), creating the `memories_fts` virtual table. Once applied, every new memory automatically generates an FTS5 entry alongside the base record.

To search memories using FTS5, query the virtual table with the `MATCH` operator:

```typescript
import { getDbInstance } from '../../src/lib/db/core.js';

const db = getDbInstance();
const rows = db.prepare(`
  SELECT id, content FROM memories_fts WHERE content MATCH ?
`).all('quantum computing');

```

## Implementing Vector Quantization

Quantization reduces embedding precision from 32-bit floats to 8-bit integers (or binary), cutting storage by 75% while preserving retrieval quality. OmniRoute handles quantization differently depending on your selected vector store.

### SQLite-vec Quantization Modes

For the SQLite backend, quantization is controlled via the `MEMORY_VEC_QUANTIZATION` environment variable. Set this in your `.env` file or shell:

```bash
MEMORY_VEC_QUANTIZATION=int8   # Options: "none", "int8", "binary"

```

The quantization logic resides in [`src/lib/memory/vectorStore.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/memory/vectorStore.ts). When `int8` is selected, the SQL placeholder is dynamically swapped for `vec_quantize_int8(?, 'unit')` during insertion. Binary quantization uses a similar mechanism for extreme compression.

### Qdrant Quantization Configuration

When using Qdrant, quantization is configured via the `qdrantQuantization` field in the memory settings. Valid values are `"none"`, `"int8"`, or `"binary"`.

The helper function `buildQuantizationConfig` in [`src/lib/memory/qdrant.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/memory/qdrant.ts) constructs the appropriate collection configuration. For quantized collections, it automatically enables `rescore: true` to maintain search accuracy:

```typescript
// Update settings via the Settings API
await fetch('http://localhost:3000/api/settings/memory', {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    memoryVectorStore: 'qdrant',
    qdrantQuantization: 'int8'
  })
});

```

## Re-indexing Memories After Configuration Changes

Changing quantization modes invalidates existing embeddings. You must re-index stored memories to apply new precision settings.

Flag all existing memories for re-indexing using the `markAllMemoriesNeedReindex` function in [`src/lib/db/memoryVec.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/memoryVec.ts):

```typescript
import { markAllMemoriesNeedReindex } from '../../src/lib/db/memoryVec.js';

const affected = markAllMemoriesNeedReindex();
console.log(`Marked ${affected} memories for re-index`);

```

The background re-indexer (`open‑sse/services/memoryReindex.ts`) processes the queue via `getMemoryReindexQueue`, regenerating embeddings with the new quantization settings. Run this service after changing any quantization configuration.

## End-to-End Usage Examples

Once configured, you can interact with the memory system through CLI tools or HTTP endpoints.

### Inserting Memories

Add content via the CLI:

```bash
omniroute memory add \
  --content "Explain quantum computing in simple terms." \
  --key "quantum-explain"

```

Or use the HTTP endpoint:

```bash
curl -X POST http://localhost:3000/api/memory \
  -H "Content-Type: application/json" \
  -d '{"content": "Explain quantum computing.", "key": "quantum"}'

```

Both methods write text to the FTS5 index and store quantized embeddings in your configured vector store.

### Hybrid Search Queries

Perform full-text searches against the FTS5 virtual table for keyword matches:

```typescript
const results = db.prepare(`
  SELECT id, content FROM memories_fts WHERE content MATCH ?
`).all('simple terms');

```

For semantic similarity, use the vector search endpoint:

```typescript
const response = await fetch('http://localhost:3000/api/memory/search', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ query: 'What is a qubit?' })
});
const semanticResults = await response.json();

```

## Summary

- **FTS5 Integration**: Migration [`022_add_memory_fts5.sql`](https://github.com/diegosouzapw/OmniRoute/blob/main/022_add_memory_fts5.sql) creates a virtual table enabling fast keyword search through SQLite's native `MATCH` syntax.
- **Vector Quantization**: Reduce storage by setting `MEMORY_VEC_QUANTIZATION` (SQLite) or `qdrantQuantization` (Qdrant) to `"int8"` or `"binary"`.
- **Storage Backends**: Choose between `"sqlite-vec"` for local SQLite storage or `"qdrant"` for external vector databases via `memoryVectorStore` settings.
- **Re-indexing Required**: Always run `markAllMemoriesNeedReindex()` after changing quantization modes to update existing embeddings.
- **Key Files**: Core logic resides in [`src/lib/memory/vectorStore.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/memory/vectorStore.ts) (SQLite quantization), [`src/lib/memory/qdrant.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/memory/qdrant.ts) (Qdrant config), and [`src/lib/db/memoryVec.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/memoryVec.ts) (settings persistence).

## Frequently Asked Questions

### What file enables FTS5 search in OmniRoute?

The migration file [`src/lib/db/migrations/022_add_memory_fts5.sql`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/migrations/022_add_memory_fts5.sql) creates the FTS5 virtual table named `memories_fts`. This file adds the full-text index on the `content` column of the memories table, allowing SQLite to perform optimized keyword searches using the `MATCH` operator.

### How do I switch from float32 to int8 quantization in SQLite?

Set the environment variable `MEMORY_VEC_QUANTIZATION=int8` before starting the application. This triggers the logic in [`src/lib/memory/vectorStore.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/memory/vectorStore.ts) to wrap SQL placeholders with `vec_quantize_int8(?, 'unit')` during insertion, automatically converting 32-bit float embeddings to 8-bit integers.

### Why must I re-index memories after changing quantization settings?

Existing embeddings were computed and stored using the previous precision format (e.g., float32). When you switch to `int8` or `binary`, the stored vectors become incompatible with the new search parameters. The `markAllMemoriesNeedReindex()` function flags all rows for regeneration, ensuring the background re-indexer in `open‑sse/services/memoryReindex.ts` recalculates embeddings with the correct quantization.

### Can I use both FTS5 and vector quantization simultaneously?

Yes. FTS5 handles lexical search on text content, while vector quantization optimizes the storage of semantic embeddings. Configure FTS5 via the migration and quantization via `MEMORY_VEC_QUANTIZATION` (SQLite) or `qdrantQuantization` (Qdrant). The systems are orthogonal—FTS5 does not affect vector storage and vice versa.