# libSQL Vector Store

The libSQL storage implementation provides a SQLite-compatible vector search [libSQL](https://github.com/tursodatabase/libsql), a fork of SQLite with vector extensions, and [Turso](https://turso.tech/) with vector extensions, offering a lightweight and efficient vector database solution. It's part of the `@mastra/libsql` package and offers efficient vector similarity search with metadata filtering.

## Installation

**npm**:

```bash
npm install @mastra/libsql@latest
```

**pnpm**:

```bash
pnpm add @mastra/libsql@latest
```

**Yarn**:

```bash
yarn add @mastra/libsql@latest
```

**Bun**:

```bash
bun add @mastra/libsql@latest
```

## Usage

```typescript
import { LibSQLVector } from "@mastra/libsql";

// Create a new vector store instance
const store = new LibSQLVector({
  id: 'libsql-vector',
  url: process.env.DATABASE_URL,
  // Optional: for Turso cloud databases
  authToken: process.env.DATABASE_AUTH_TOKEN,
});

// Create an index
await store.createIndex({
  indexName: "myCollection",
  dimension: 1536,
});

// Add vectors with metadata
const vectors = [[0.1, 0.2, ...], [0.3, 0.4, ...]];
const metadata = [
  { text: "first document", category: "A" },
  { text: "second document", category: "B" }
];
await store.upsert({
  indexName: "myCollection",
  vectors,
  metadata,
});

// Query similar vectors
const queryVector = [0.1, 0.2, ...];
const results = await store.query({
  indexName: "myCollection",
  queryVector,
  topK: 10, // top K results
  filter: { category: "A" } // optional metadata filter
});
```

## Constructor Options

**url:** (`string`): libSQL database URL. Use ':memory:' for in-memory database, 'file:dbname.db' for local file, or a libSQL-compatible connection string like 'libsql://your-database.turso.io'.

**authToken?:** (`string`): Authentication token for Turso cloud databases

**syncUrl?:** (`string`): URL for database replication (Turso specific)

**syncInterval?:** (`number`): Interval in milliseconds for database sync (Turso specific)

## Methods

### createIndex()

Creates a new vector collection. The index name must start with a letter or underscore and can only contain letters, numbers, and underscores. The dimension must be a positive integer.

**indexName:** (`string`): Name of the index to create

**dimension:** (`number`): Vector dimension size (must match your embedding model)

**metric?:** (`'cosine' | 'euclidean' | 'dotproduct'`): Distance metric for similarity search. Note: Currently only cosine similarity is supported by libSQL. (Default: `cosine`)

### upsert()

Adds or updates vectors and their metadata in the index. Uses a transaction to ensure all vectors are inserted atomically - if any insert fails, the entire operation is rolled back.

**indexName:** (`string`): Name of the index to insert into

**vectors:** (`number[][]`): Array of embedding vectors

**metadata?:** (`Record<string, any>[]`): Metadata for each vector

**ids?:** (`string[]`): Optional vector IDs (auto-generated if not provided)

### query()

Searches for similar vectors with optional metadata filtering.

**indexName:** (`string`): Name of the index to search in

**queryVector:** (`number[]`): Query vector to find similar vectors for

**topK?:** (`number`): Number of results to return (Default: `10`)

**filter?:** (`Filter`): Metadata filters

**includeVector?:** (`boolean`): Whether to include vector data in results (Default: `false`)

**minScore?:** (`number`): Minimum similarity score threshold (Default: `0`)

### describeIndex()

Gets information about an index.

**indexName:** (`string`): Name of the index to describe

Returns:

```typescript
interface IndexStats {
  dimension: number;
  count: number;
  metric: "cosine" | "euclidean" | "dotproduct";
}
```

### deleteIndex()

Deletes an index and all its data.

**indexName:** (`string`): Name of the index to delete

### listIndexes()

Lists all vector indexes in the database.

Returns: `Promise<string[]>`

### truncateIndex()

Removes all vectors from an index while keeping the index structure.

**indexName:** (`string`): Name of the index to truncate

### updateVector()

Update a single vector by ID or by metadata filter. Either `id` or `filter` must be provided, but not both.

**indexName:** (`string`): Name of the index containing the vector

**id?:** (`string`): ID of the vector entry to update (mutually exclusive with filter)

**filter?:** (`Record<string, any>`): Metadata filter to identify vector(s) to update (mutually exclusive with id)

**update:** (`object`): Update data containing vector and/or metadata

**update.vector?:** (`number[]`): New vector data to update

**update.metadata?:** (`Record<string, any>`): New metadata to update

### deleteVector()

Deletes a specific vector entry from an index by its ID.

**indexName:** (`string`): Name of the index containing the vector

**id:** (`string`): ID of the vector entry to delete

### deleteVectors()

Delete multiple vectors by IDs or by metadata filter. Either `ids` or `filter` must be provided, but not both.

**indexName:** (`string`): Name of the index containing the vectors to delete

**ids?:** (`string[]`): Array of vector IDs to delete (mutually exclusive with filter)

**filter?:** (`Record<string, any>`): Metadata filter to identify vectors to delete (mutually exclusive with ids)

## Response Types

Query results are returned in this format:

```typescript
interface QueryResult {
  id: string;
  score: number;
  metadata: Record<string, any>;
  vector?: number[]; // Only included if includeVector is true
}
```

## Error Handling

The store throws specific errors for different failure cases:

```typescript
try {
  await store.query({
    indexName: "my-collection",
    queryVector: queryVector,
  });
} catch (error) {
  // Handle specific error cases
  if (error.message.includes("Invalid index name format")) {
    console.error(
      "Index name must start with a letter/underscore and contain only alphanumeric characters",
    );
  } else if (error.message.includes("Table not found")) {
    console.error("The specified index does not exist");
  } else {
    console.error("Vector store error:", error.message);
  }
}
```

Common error cases include:

- Invalid index name format
- Invalid vector dimensions
- Table/index not found
- Database connection issues
- Transaction failures during upsert

## Usage Example

### Local embeddings with fastembed

Embeddings are numeric vectors used by memory's `semanticRecall` to retrieve related messages by meaning (not keywords). This setup uses `@mastra/fastembed` to generate vector embeddings.

Install `fastembed` to get started:

**npm**:

```bash
npm install @mastra/fastembed@latest
```

**pnpm**:

```bash
pnpm add @mastra/fastembed@latest
```

**Yarn**:

```bash
yarn add @mastra/fastembed@latest
```

**Bun**:

```bash
bun add @mastra/fastembed@latest
```

Add the following to your agent:

```typescript
import { Memory } from "@mastra/memory";
import { Agent } from "@mastra/core/agent";
import { LibSQLStore, LibSQLVector } from "@mastra/libsql";
import { fastembed } from "@mastra/fastembed";

export const libsqlAgent = new Agent({
  id: "libsql-agent",
  name: "libSQL Agent",
  instructions:
    "You are an AI agent with the ability to automatically recall memories from previous interactions.",
  model: "openai/gpt-5.1",
  memory: new Memory({
    storage: new LibSQLStore({
      id: 'libsql-agent-storage',
      url: "file:libsql-agent.db",
    }),
    vector: new LibSQLVector({
      id: 'libsql-agent-vector',
      url: "file:libsql-agent.db",
    }),
    embedder: fastembed,
    options: {
      lastMessages: 10,
      semanticRecall: {
        topK: 3,
        messageRange: 2,
      },
      generateTitle: true, // Explicitly enable automatic title generation
    },
  }),
});
```

## Related

- [Metadata Filters](https://mastra.ai/reference/rag/metadata-filters)