Skip to main content
PostgreSQL applications often start with built-in full-text search or extensions such as pgvector and pg_search. As the application grows, both the size of each search dataset and the number of independent datasets can become important. A character-chat service may need separate search histories for each user’s character and session. A coding service may need separate datasets for users, workspaces, and repositories. LambdaDB lets you organize search around those application boundaries:
  • No collection count limit: create collections for the datasets your application needs, without consolidating unrelated data to fit a collection quota.
  • No per-collection fixed fee: an inactive collection does not incur a fixed charge just for existing. Stored data remains subject to storage charges, and reads and writes are billed when used.
  • No shard configuration as a collection grows: LambdaDB handles distributed search execution internally. Shard counts and placement are not exposed as user settings, so you do not have to manage them as the dataset grows.
Keep PostgreSQL as the source of truth for application data, transactions, and permissions, and use LambdaDB for the derived search data. This guide explains when that separation is useful, how to choose collection boundaries, and what to review before changing your search path. See Collection limits, Architecture, and Understanding costs for the underlying service behavior.

Two ways search workloads grow

The second pattern matters even when each dataset is small. For example, a service may retain many chat sessions or repositories while only a small subset receives requests at any given time. Keeping those datasets separate does not require paying a fixed fee for every idle LambdaDB collection. Measure both patterns together: a large population of inactive collections, many small active collections, and a few large or busy collections. Collection count, total stored bytes, active dataset count, and request volume describe different parts of the workload.

Choose collection boundaries

Start with the unit your application searches, authorizes, rebuilds, and deletes independently. The following are design examples, not requirements to create a physical PostgreSQL table for every entity. If multiple users share the same repository and permissions, a shared repository collection may be appropriate. If users have private changes or different visibility, preserve those differences in the collection or query design. Shared character knowledge can similarly be a separate dataset from private conversation history.

Decide how far to split

Choose a boundary that matches common queries and independent lifecycle operations. Unlimited collection count lets you preserve those boundaries; it does not require a collection for every row or entity. For example, keep private session memory separate from shared character knowledge when they have different permissions and lifecycles, and retrieve from both explicitly when needed. For any shared collection, evaluate filtered recall and enforce authorization on every query. For separate collections, account for the requests and result merging needed by searches that span datasets.

Internal sharding and user-configured partitions

Sharding and partitioning serve different purposes here: In a sharded search system, a query generally fans out across all shards within its search scope. Some services require users to configure those shards. LambdaDB handles that distribution internally; this comparison explains the operational work you do not need to manage. Partitioning is an application-visible feature. For example, configure a shared collection to partition by tenant_id, then supply partitionFilter for the authorized tenant on each scoped search. LambdaDB excludes unselected physical partitions before searching. Omitting partitionFilter leaves all partitions in the search scope. An ordinary query predicate such as knn.filter restricts matching documents; it does not substitute for explicit partition selection. See partition configuration and the partition-filter request example. Collection boundaries, partition selection, and document predicates can work together; shard configuration remains internal.

Shared tables and separate search datasets

A PostgreSQL table can feed multiple LambdaDB collections, routed by a stable tenant, chat, or repository identity. Existing separate PostgreSQL tables can also map to separate collections. You do not need to redesign the source schema to match the search layout, but your ingestion code must implement and maintain that mapping. Using one shared table and a tenant filter is another valid starting point. Review its search behavior before treating it as equivalent to separate indexes: pgvector documents that sharing an approximate index between tenants can affect recall and speed, and suggests separate tables or list partitioning for tenant isolation. Its filtering guidance also covers exact search over filtered rows, partial indexes, and iterative scans. PostgreSQL table partitioning introduces its own tradeoffs. PostgreSQL’s partitioning guidance discusses planning time and memory costs when partition counts grow. Evaluate the actual query and maintenance workload rather than assuming that either one shared index or one partition per tenant is always preferable.

Routing, permissions, and versions

Resolve the target collection in your backend from the authenticated user’s allowed dataset. A collection boundary scopes the search corpus; it does not automatically reproduce PostgreSQL RLS or allocate dedicated compute. Keep project API keys on the backend and authorize collection and ref selection before returning documents, snippets, or scores. If you combine multiple source tables in one collection, make document IDs unique across those tables. If a row moves between datasets, remove its old search representation as well as writing the new one. Use branches and tags when a single dataset needs different search histories or pinned versions. Application chat branches and Git revisions do not automatically become LambdaDB refs; your application must maintain that relationship. Schemas and retention are configured at the collection level. Search requests target one collection. If a user searches several repositories or combines shared character knowledge with private chat memory, plan application-side requests, result merging, authorization, and their combined cost.

Check search compatibility

The current integration path uses LambdaDB’s REST API or SDKs and application-owned ingestion. The Migration CLI does not currently provide a PostgreSQL source connector. A native PostgreSQL extension is under evaluation; SQL-preserving integration is not a released compatibility layer. The examples below use the available API path. Review the exact PostgreSQL version, installed extensions, index definitions, and production queries. Sharing a vector type or the term BM25 does not establish identical query syntax, results, or transaction behavior. Use the index type reference for field mappings. Export original text rather than serialized tsvector values. Convert IDs and source values explicitly; review NULL or missing values, timestamps, arrays, and JSON structures. Dense, sparse, half-precision, and binary vector representations need separate mapping decisions.

Vector operators and result handling

In the tables below, API mapping means a documented LambdaDB operation exists, rewrite required means the application must reconstruct the behavior, and no direct equivalent means there is no corresponding operation in the documented API. These are API mappings, not SQL compatibility certification; the REST/SDK path requires application changes in all cases. See pgvector’s operator definitions, LambdaDB vector metrics, and vector filters. Metric selection preserves the intended comparison; ANN candidate selection and score representation still need validation.

Text, hybrid, and relational features

See query string syntax, hybrid queries, and query limits. For each production query, record the source query, target request, expected scope, and acceptable result differences before cutover. Suppose PostgreSQL stores one session in chat_session_42, with id, body, and embedding vector(3) columns. Map its search data to a LambdaDB collection named chat-session-42. Three-dimensional vectors keep these examples short; use your actual model’s dimensions and the same embedding model for documents and queries.

Create the search collection

Send this body to POST /projects/{projectName}/collections on your regional base URL. See Create a collection for authentication and SDK examples.
Export rows into documents with a stable string id, the original body, and the numeric embedding array. Load them through upsert or bulk upsert. This is an application-owned export and load step, not an automatic table connection.

Vector retrieval

Existing pgvector query:
LambdaDB request body for POST /projects/{projectName}/collections/chat-session-42/query:
This preserves the intended session search scope and cosine metric. It does not promise identical ANN neighbors. PostgreSQL returns a distance in the selected distance column; LambdaDB returns result items containing doc and score, ordered by relevance. Adapt result handling and validate any score threshold rather than copying a distance threshold. See Search overview and Vector query. For a shared collection, configure indexed scope fields and put the authorized scope inside knn.filter. If the collection is partitioned on that scope field, also use top-level partitionFilter to exclude unrelated partitions from the search. Filtering an already truncated top-k response can leave too few results. A session-specific collection avoids needing a session predicate to select that corpus, while backend authorization is still required.

Text retrieval

A PostgreSQL built-in FTS predicate might be:
The corresponding search intent can be expressed in the same LambdaDB collection with:
The explicit AND requests both terms; unqualified terms separated by spaces in LambdaDB query strings are optional clauses. This example returns a ranked, limited result set, while the SQL example selects all matches without ranking. Matching can also differ because PostgreSQL text configurations and LambdaDB analyzers are distinct. Review actual queries and relevance judgments using the PostgreSQL text-search documentation and LambdaDB query syntax.

Keep the search data current

For ongoing use, define how committed PostgreSQL inserts, updates, and deletes reach LambdaDB after the initial load. A custom integration can use a durable outbox or CDC pipeline, but must handle the snapshot-to-change-stream handoff, retries, ordering, and recovery. There is no automatic synchronization from creating a collection. Track source progress and search visibility separately. LambdaDB consistentRead: true can include eligible pending writes already received by the selected branch; it cannot retrieve PostgreSQL changes that your integration has not delivered. Pending bulk imports remain invisible until committed. See Consistent reads. Apply permission changes and deletions before exposing stale search content. A later PostgreSQL permission check does not undo disclosure of snippets or metadata already returned to the caller. If local checks remove candidates, define how to obtain enough permitted results rather than assuming a fixed over-fetch factor always returns k matches.

Evaluate performance and total cost

Compare a tuned PostgreSQL baseline with the proposed collection layout. Keep embeddings, data, search quality targets, and traffic distributions comparable. Inactive collections have no per-collection fixed fee, but retained storage still contributes to cost. Read usage reflects the collection’s search scope, or the selected partitions when using partitionFilter, and has a per-request minimum. Collection boundaries, partition selection, and searches across multiple collections therefore affect the estimate. Use Understanding costs and the current pricing instead of treating either collection count or query count alone as the bill.

Example: many retained chats, few active chats

This hypothetical sizing example illustrates billing, not measured capacity or a PostgreSQL cost comparison. Assume a 30-day month on the paid plan, decimal units (1 GB = 1,000 MB, 1 PB = 1,000,000 GB), and an already loaded dataset:
  • 100,000 session collections, each occupying an average of 10 MB of billed physical storage for the month.
  • The same 1,000 collections receive 100 queries per day each; the other 99,000 receive no requests.
  • Every query targets one collection, its read-usage size is below 1 GB, and consistentRead is false. Each query therefore uses the 1 GB read minimum.
  • There are no writes, deletes, rebuilds, managed embedding calls, or additional fetch/list requests during this example month.
The inactive collections contribute 990 GB of the stored data, but no read usage or fixed collection fee. If all collections become inactive while the same data is retained, read usage falls to zero and the illustrated storage charge remains $330. Removing the data is a different lifecycle decision from simply not querying it. Rates were checked against public pricing on September 18, 2026. Returned query data and retention storage for deleted data are temporarily free; the published rates after the promotion are 0.05/GBreturnedand0.05/GB returned and 0.10/GB-month of retention storage, with advance notice before billing starts. Include those meters when forecasting beyond the promotion. Initial loading, subsequent writes, PostgreSQL, synchronization infrastructure, and network-provider charges are outside this subtotal. Before switching production traffic, validate the mapping and representative queries, exercise update and delete propagation, and run shadow searches through the application. Keep a tested route back to PostgreSQL search until correctness, quality, latency, and total cost meet your requirements. These checks establish the benefit for your workload; there is no universal row-count threshold for moving search out of PostgreSQL.

Need help planning your migration?

Not sure how to map your PostgreSQL search workload to LambdaDB? Email support@lambdadb.ai or ask in the LambdaDB community Slack for help with collection design, query compatibility, and migration next steps. A brief description of your current search extensions, approximate data and tenant/session counts, and the problem you want to solve is enough to start. If useful, include a sanitized example query so we can discuss the mapping in concrete terms.