QUESTPIE
Operate in Production

Search

Full-text search with PostgreSQL FTS and pgvector embeddings.

QUESTPIE supports full-text search using PostgreSQL's built-in FTS capabilities and optional embedding-based semantic search with pgvector.

Currently, PostgreSQL FTS and pgvector are the only implemented search adapters. External services like Meilisearch or Elasticsearch are not yet supported.

Making Collections Searchable

Add .searchable() to index a collection for full-text search:

src/questpie/server/collections/posts.ts
import { collection } from "#questpie/factories"

export default collection("posts")
  .fields(({ f }) => ({
    title: f.text(255).required(),
    body: f.textarea(),
    tags: f.text(500),
  }))
  .searchable({
    content: (record) => `${record.title} ${record.body ?? ""} ${record.tags ?? ""}`,
    metadata: (record) => ({
      published: record.status === "published",
    }),
  })
OptionTypeDescription
content(record) => stringExtracts plain text for full-text indexing. Called on create/update.
metadata(record) => objectStructured metadata for faceted filtering.

How It Works

When a record is created or updated:

  1. The content function extracts plain text from the record
  2. PostgreSQL generates a tsvector for the text using the configured language
  3. A GIN index enables fast full-text queries
  4. BM25 ranking orders results by relevance
const results = await client.search.search({
  query: "haircut styles",
  collections: ["posts", "services"],
  limit: 20,
})

Search Options

OptionTypeDescription
querystringSearch query (supports PostgreSQL tsquery syntax)
collectionsstring[]Limit search to specific collections
limitnumberMaximum results (default: 50)

From routes or hooks:

handler: async ({ search }) => {
  const results = await search.search({
    query: "booking confirmation",
    collections: ["posts"],
  })
  return results
}

Embedding-Based Search (pgvector)

For semantic search using vector embeddings:

.searchable({
  content: (record) => record.title + " " + record.body,
  embeddings: {
    enabled: true,
    dimensions: 1536,
    model: "text-embedding-3-small",
  },
})

This stores vector embeddings alongside the text index, enabling similarity-based queries that understand meaning rather than just keywords.

On this page