AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides guidance for working with Lakebase Postgres on Neon. It covers connection management, schema migrations, branching workflows, autoscaling, and performance diagnostics. It is designed to assist with database operations including inspecting schemas, optimizing egress, and implementing search features like vector, full-text, and hybrid search. The skill distinguishes between pooled and direct connection usage, provides diagnostic tools for performance analysis, and outlines procedures for managing compute resources and database branches.
What it does
- Provides best practices for pooled versus direct connection usage
- Guides schema migration and branching workflows including schema-only and branch-per-PR
- Offers diagnostic tools for identifying egress anti-patterns and query performance issues
- Supports configuration of autoscaling, scale-to-zero, and read replicas
- Facilitates implementation of semantic, full-text, and hybrid search features
- Assists with compute management tasks like resizing, suspending, and restarting
When to use it
- When working with an existing DATABASE_URL, SQL, or database schema
- When diagnosing high database bills or network egress issues
- When planning isolated environments for migration testing or preview deployments
- When implementing vector, full-text, or hybrid search capabilities
- When needing to inspect database performance or compute behavior
Advantages
- Provides clear distinctions between pooled and direct connection use cases
- Offers structured workflows for database branching and migration testing
- Includes specific diagnostic queries for identifying egress and performance bottlenecks
- Integrates with Neon CLI and MCP for operational tasks
- Supports modern development patterns like branch-per-PR
Usage examples
- “How do I optimize my database egress costs?”
- The agent will guide you through diagnosing top egress contributors using pg_stat_statements, analyzing your codebase for anti-patterns, and applying fixes like column selection and pagination.
- “Create a new branch for testing my schema migration.”
- The agent will verify your CLI or MCP authentication and execute the branch creation, providing you with the connection string for the new isolated environment.
- “Which connection string should I use for my migration script?”
- The agent will explain that migrations require a direct (unpooled) connection and help you identify the correct string without the -pooler suffix.
- “How can I implement vector search in my Neon database?”
- The agent will provide guidance on using Lakebase Search, including setting up the necessary extensions and managing the search implementation via your ORM.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/neondatabase/neon-postgres/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip neon-postgres.zip -d .agents/skills
Documentation by Neon
FIRST: Use the parent neon skill for a Neon overview, getting started with Neon, Neon development best practices, and more.
If the neon skill is not installed, fetch it from https://neon.com/docs/ai/skills/neon/SKILL.md or install it with:
neon skills -s neon -yLakebase Postgres
Lakebase Postgres is the database at the core of Neon. It runs on the lakebase architecture — OLTP built directly on cloud object storage — which decouples storage from compute to offer autoscaling, branching, instant restore, and scale-to-zero. It's fully compatible with Postgres and works with any language, framework, or ORM that supports Postgres.
It is the same database whether you reach it through Neon or through Databricks; this skill covers the Neon access path.
Login, users, sessions, and @neon/auth belong in neon-auth.
Live queries, reactive UIs, and realtime data belong in neon-realtime.
Setup Flow
1. Select the organization and project
If a DATABASE_URL is already supplied (prompt, environment, or repo) or a .neon file points at a project, use it. Do not list organizations or create a second project for schema work.
Otherwise use the CLI (default) or MCP server to list organizations and projects. Let the user select an existing project or create a new one.
2. Get the connection string
If a DATABASE_URL is already supplied, use it. Do not fetch another through the CLI or MCP.
Otherwise use the CLI (default), neon env pull, or the MCP server to get the connection string. Store it in .env as DATABASE_URL. Read the file first before modifying it, to avoid overwriting existing values.
When to use pooled vs direct connections
| Use case | Connection type |
|---|---|
| Web applications, serverless functions | Pooled (-pooler) |
| Schema migrations | Direct |
| pg_dump / pg_restore | Direct |
| Logical replication | Direct |
| Long-running analytics with temp tables | Direct |
| Admin tasks needing SET or session state | Direct |
| LISTEN / NOTIFY | Direct |
3. Pick the connection method and driver
Preserve the existing ORM and driver. For new TypeScript schema work with no established choice, Drizzle is a suggestion: https://neon.com/docs/guides/drizzle.md. Refer to the connection methods guide to pick the correct driver based on how the runtime treats your code: https://neon.com/docs/connect/choose-connection.md.
Driver notes:
On Vercel, use
node-postgres(npm install pg) with Vercel Fluid compute andimport { attachDatabasePool } from "@vercel/functions";On Cloudflare, use
node-postgreswith Cloudflare HyperdriveOn Neon Functions, use
node-postgres, as the functions are long-running and reuse the pool across requests.Use the
@neondatabase/serverlessdriver for serverless and edge environments (for example, when using Netlify) — HTTP transport for one-shot queries, WebSocket for transaction support. Link: https://neon.com/docs/serverless/serverless-driver.md
4. Set up the schema
Manage schemas and migrations as code. Avoid running ad hoc schema migrations against your database, since they're hard to manage.
If you're using an ORM, follow your ORM's best practices to manage schemas and migrations. For example, if using Drizzle, only use Drizzle for schema and migration management unless instructed otherwise.
Branching
Use this when the user is planning isolated environments, schema migration testing, preview deployments, or branch lifecycle automation.
Key points:
Branches are instant, copy-on-write clones (no full data copy).
Each branch has its own compute endpoint.
Use the neon CLI or MCP server to create, inspect, and compare branches.
Link: https://neon.com/docs/introduction/branching.md
For detailed branch creation workflows (normal vs schema-only branches, reset-from-parent, CLI/MCP selection, and CI/CD patterns), read Branching workflows.
Migrations
Test a migration on a branch of production, against production-like data, before applying it to production.
Use a direct (non-pooled) connection string when you run the migration, not a pooled one. neon connection-string returns the direct string by default; make sure the hostname does not include the -pooler suffix.
Egress Optimization
Use this when a user reports high database bills, unexpected network transfer, egress spikes, query overfetching, or wants a cost-efficiency review of database query patterns.
Before editing code, read Egress optimization. Audit all five patterns: unused columns, missing pagination, repeated static reads, application-side aggregation, and JOIN duplication. Do not stop after fixing SELECT *.
Work in four steps: diagnose which queries transfer the most data, analyze the code behind them, fix the anti-patterns, then verify that behavior is preserved and transfer drops.
Troubleshooting and Neon-Specific Performance
Use Neon's predefined, read-only diagnostics before writing catalog queries by hand. The Neon CLI neon inspect db subcommands and the Neon MCP server's inspect_database tool run the same checks.
This section covers Neon-specific diagnostic tools, compute cache behavior, and platform signals. When the evidence points to generic Postgres work such as rewriting a query, choosing an index, changing a schema, or interpreting plan nodes, load the postgres-best-practices skill and carry the diagnostic evidence into that workflow.
Docs:
Query performance: https://neon.com/docs/postgresql/query-performance.md
pg_stat_statements: https://neon.com/docs/extensions/pg_stat_statements.mdNeon Local File Cache: https://neon.com/docs/extensions/neon.md
Choose CLI or MCP
Prefer the Neon CLI when terminal access and authentication are available:
neon inspect db <check>The CLI resolves the project and branch from the current Neon context. Use --project-id, --branch, and --database-name to override it. Omit --database-name to inspect every database on the branch. Use --db-url only when inspecting a Postgres database directly instead of resolving it through the Neon API.
When using Neon MCP, call inspect_database with projectId and one check. Pass branchId, databaseName, or computeId only when needed. Omit databaseName to inspect all databases on the branch. Increase limit only when the result says it was truncated.
Pick the Diagnostic
| Symptom or question | Checks |
|---|---|
| Which relations consume storage? | table-sizes, index-sizes |
| Is an index unused or a table scanned heavily? | unused-indexes, seq-scans |
| What has run for 5+ minutes or holds locks? | long-running-queries, locks |
| Which queries consume the most total time? | outliers |
| Which queries run most often? | calls |
| Does the active data fit in compute cache? | lfc-hit-rate, working-set |
| Is autovacuum behind or is space wasted? | vacuum-stats, bloat |
| Is logical replication healthy? | replication-slots, subscriptions |
Do not confuse these checks:
long-running-queriesreports statements running right now for more than five minutes.outliersranks the top queries by cumulative execution time since statistics were reset. It does not rank by mean latency.callsranks by execution count over the same statistics history.
outliers and calls require pg_stat_statements. lfc-hit-rate and working-set require the neon extension. If a check reports a missing extension, ask before running the suggested CREATE EXTENSION statement because installing an extension modifies the database.
Interpret Results Safely
Treat
unused-indexesas a candidate list, not permission to drop indexes. Confirm the observation window, constraints, and workload before removal.A sequential scan can be correct for a small table or a query reading much of a table. Check table size, selectivity, and the query plan before adding an index.
bloatis a statistical estimate. Confirm the impact and plan locks or maintenance beforeVACUUM FULL,REINDEX, or similar remediation.Cache and Postgres statistics reset when compute restarts, including scale-to-zero suspension. Run a representative workload before interpreting fresh
lfc-hit-rate,working-set,vacuum-stats, orpg_stat_statementsresults.Compute-wide checks (
lfc-hit-rate,working-set, andreplication-slots) run once even when inspecting every database.One failing database can fail an all-databases inspection; retry the relevant check with an explicit
databaseNameto isolate it.
Inspect Neon Cache Behavior Per Query
Standard EXPLAIN (ANALYZE, BUFFERS) reports Postgres shared-buffer activity, but it does not show Neon's Local File Cache (LFC) or page prefetching. For a safe read-only query, add Neon's FILECACHE and PREFETCH options:
EXPLAIN (ANALYZE, BUFFERS, PREFETCH, FILECACHE)
SELECT ...;File cache: hitscounts pages found in the compute's LFC.File cache: missescounts pages not found in the LFC and fetched from database storage.Prefetch: hits,misses,expired, andduplicatesshow how effectively Neon fetched pages before the executor requested them.
FILECACHE and PREFETCH provide metrics for this query and do not require the neon extension. By contrast, neon inspect db lfc-hit-rate and working-set provide compute-wide statistics and do require the extension.
The MCP explain_sql_statement tool can produce a standard plan but does not expose FILECACHE or PREFETCH options. To collect those Neon-specific metrics through MCP, use run_sql with the explicit, read-only EXPLAIN statement above.
Because ANALYZE executes the statement, use it only when execution is safe; do not run it autonomously for mutating SQL. Compare cold- and warm-cache runs carefully because the first execution can populate the cache and materially change later results.
Performance Workflow
Reproduce the symptom and note its time window.
Run the smallest relevant
inspectchecks from the table above.Identify a specific query before changing schema or compute. Use MCP
explain_sql_statementfor a standard plan, or the Neon-specificEXPLAINabove when LFC or prefetch behavior matters.If the bottleneck is query shape, indexing, schema, locking, or vacuum behavior, load
postgres-best-practicesand carry forward the inspection results and query plan. Keep Neon compute, cache, connection, and platform decisions in this skill.Re-run the same check and workload to verify the change.
Use MCP list_slow_queries instead of inspect_database when the user specifically needs queries ranked by average execution time with a custom threshold and limit. Outside the explicit EXPLAIN case above, use run_sql only for read-only diagnostic SQL when the predefined checks do not answer the question.
Computes
Use this when the user wants to resize a compute, change its scale-to-zero timeout, or start, suspend, restart, or delete it.
Manage computes with neon postgres computes. neon pg and neon lakebase are aliases of neon postgres.
neon postgres computes list # --branch <branch> or the branch .neon pins; --all-branches for the project
neon postgres computes get <compute-id>
neon postgres computes update <compute-id> --cu 0.25-2 --suspend-timeout 300
neon postgres computes restart <compute-id> # also start, suspend, deleteupdate sends only the flags you pass (--cu, --suspend-timeout, --name, --disabled) and fails when you pass none. Each change waits until Neon applies it; update, start, suspend, and restart then print the compute. With --no-wait the command returns once the API accepts the change; find the operation with neon operations list and check it with neon operations get <operation-id>. Add a compute, such as a read replica, with neon branches add-compute <branch>.
Autoscaling
Use this when the user needs compute to scale automatically with workload and wants guidance on CU sizing and runtime behavior.
Set a compute's autoscaling range with neon postgres computes update <compute-id> --cu <min>-<max> (for example --cu 0.25-2), or a fixed size with --cu 2.
Link: https://neon.com/docs/introduction/autoscaling.md
Scale to Zero
Use this when optimizing idle costs and discussing suspend/resume behavior, including cold-start trade-offs.
Key points:
Idle computes suspend automatically after a default of 5 minutes. Change the timeout with
neon postgres computes update <compute-id> --suspend-timeout <seconds>:0uses the plan default and-1disables suspension. Free cannot change it, Launch can only enable or disable suspension, and Scale can set any value from 60 to 604800 (one week).First query after suspend typically has a cold-start penalty (around hundreds of ms)
Storage remains active while compute is suspended.
Link: https://neon.com/docs/introduction/scale-to-zero.md
Keep hot reads off Postgres
Scale to zero only suspends an idle compute. When the same rarely changing rows (config, categories, feature flags) are read on every request, cache them outside Postgres, for example in Upstash Redis with a TTL. Cached reads cut egress and cold-start latency, and let an otherwise idle compute stay suspended.
Instant Restore
Use this when the user needs point-in-time recovery or wants to restore data state without traditional backup restore workflows.
Key points:
History windows for instant restore depend on plan limits.
Users can create branches from historical points-in-time.
Time Travel queries can be used for historical inspection workflows.
Link: https://neon.com/docs/introduction/branch-restore.md
Read Replicas
Use this for read-heavy workloads where the user needs dedicated read-only compute without duplicating storage.
Key points:
Replicas are read-only compute endpoints sharing the same storage.
Creation is fast and scaling is independent from primary compute.
Typical use cases: analytics, reporting, and read-heavy APIs.
Link: https://neon.com/docs/introduction/read-replicas.md
Connection Pooling
Use this when the user is in serverless or high-concurrency environments and needs safe, scalable Postgres connection management.
Key points:
Neon pooling uses PgBouncer.
Add
-poolerto endpoint hostnames to use pooled connections.Pooling is especially important in serverless runtimes with bursty concurrency.
Link: https://neon.com/docs/connect/connection-pooling.md
IP Allow Lists
Use this when the user needs to restrict database access by trusted networks, IPs, or CIDR ranges.
Link: https://neon.com/docs/introduction/ip-allow.md
Logical Replication
Use this when integrating CDC pipelines, external Postgres sync, or replication-based data movement.
Key points:
Neon supports native logical replication workflows.
Useful for replicating to/from external Postgres systems.
Link: https://neon.com/docs/guides/logical-replication-guide.md
Lakebase Search
Use Lakebase Search for semantic, full-text, and hybrid search:
For semantic search, including generating embeddings with the Neon AI Gateway, read Vector search.
For full-text search with BM25 ranking, read Full-text search.
For combining semantic and lexical results with fusion or reranking, read Hybrid search.
For managing any of the above through Drizzle ORM, read Managing Lakebase Search with Drizzle.
Links:
Gotchas
Pooled vs direct connections: use the direct URL for migrations, dumps, and replication
Neon gives you two connection strings for the same database: a pooled one (hostname with the -pooler suffix) and a direct/unpooled one (no -pooler suffix). neon env pull writes them as DATABASE_URL and DATABASE_URL_UNPOOLED. The pooled connection routes through PgBouncer in transaction mode, which doesn't support session-level operations. Choose the right one:
Pooled (
DATABASE_URL) — your application's normal query traffic, especially serverless and connection-per-request workloads.Direct (
DATABASE_URL_UNPOOLED) — schema migrations (Prisma Migrate, Drizzle Kit, Alembic, and others),pg_dump/pg_restore, logical replication,LISTEN/NOTIFY, and anything relying onSETor other session state.
Running migrations, dumps, or replication over the pooled connection can fail, and never in a way that names pooling: prepared statement "s0" already exists from Prisma Migrate, a SET search_path that doesn't persist past its own transaction so the next query reports relation "mytable" does not exist, or a write intermittently hitting a read-only transaction (SQLSTATE 25006) that a pooled backend inherited from an earlier client. Migration tools generally take both strings at once — Prisma's directUrl alongside url — so point that at the direct one rather than swapping DATABASE_URL and losing pooling for the application. See https://neon.com/docs/connect/connection-pooling.md.
Files
- ATTRIBUTION.mdAdded by AutoGineer870 B
- LICENSELicence file added by AutoGineer11.1 KiB
- SKILL.md18.9 KiB
- references/branching.md12.4 KiB
- references/egress-optimization.md9.3 KiB
- references/full-text-search.md4.2 KiB
- references/hybrid-search.md10.4 KiB
- references/lakebase-search-drizzle.md9.9 KiB
- references/vector-search.md12.2 KiB
references/hybrid-search.md
Hybrid Search
Use hybrid search when either semantic similarity or exact vocabulary can identify a relevant document. Run vector and full-text search separately, then combine their results with fusion or reranking.
Lakebase Search requires Postgres 16 or later. Hybrid search uses both extensions:
CREATE EXTENSION IF NOT EXISTS lakebase_vector CASCADE;
CREATE EXTENSION IF NOT EXISTS lakebase_text;lakebase_vector installs pgvector through CASCADE; lakebase_text has no extension dependency. Both rely on preloaded libraries that Neon enables by default. If the project customized its preloaded-library list, confirm both libraries remain enabled.
Prepare a table with both vector and text-search columns:
CREATE TABLE documents (
id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
title text NOT NULL,
body text NOT NULL,
embedding vector(1024),
body_tsv tsvector GENERATED ALWAYS AS
(to_tsvector('english', body)) STORED
);The 1024-dimensional column is an example. Set it to the output dimension of your selected embedding model. Generate document embeddings in batches and embed each query with the same model and dimensions; Vector search shows the AI Gateway calls. Follow any model-specific query instructions, while keeping the original query text for BM25. Choose a PostgreSQL text-search configuration appropriate for the corpus.
Create and validate each retriever independently before combining them. Follow Vector search and Full-text search for their indexes, query operators, and tuning.
Choose how to order the combined results:
Jev reranking: retrieve vector and full-text search candidates, deduplicate by document ID, score each candidate with Jev, and take the final top results.
Reciprocal Rank Fusion (RRF): fuse the retrievers' ranks instead of their incomparable vector distances and BM25 scores, with no additional model call.
Jev can score the deduplicated candidate pool directly. RRF is optional when you want to prioritize or trim a larger pool before reranking, or provide a model-free fallback. Measure relevance and added latency on your corpus to choose a path.
Rerank with Jev
Retrieve up to 40 candidates per retriever and deduplicate with UNION. Bind the query embedding as $1 and the original query text as $2:
WITH vector_candidates AS (
SELECT id
FROM documents
WHERE embedding IS NOT NULL
ORDER BY embedding <=> $1::vector
LIMIT 40
),
keyword_candidates AS (
SELECT id
FROM (
SELECT
id,
body_tsv <@> to_bm25query(
to_tsvector('english', $2),
'documents_body_bm25'::regclass
) AS score
FROM documents
) AS keyword_scored
WHERE score < 0
ORDER BY score, id
LIMIT 40
),
candidate_ids AS (
SELECT id FROM vector_candidates
UNION
SELECT id FROM keyword_candidates
)
SELECT d.id, d.title, d.body
FROM candidate_ids AS c
JOIN documents AS d ON d.id = c.id
ORDER BY d.id;Apply the same access-control and tenant filters inside both retrievers, before their limits. Take the final top results only after Jev scoring.
Batch yes/no relevance questions with the query shared in state and each candidate in its own question's instructions. Sort the returned probabilities in descending order; equal probabilities keep the input order.
Use Neon's provider with the Vercel AI SDK. Requirements:
Install the tested versions:
npm install @neon/[email protected] [email protected]. Decision models require AI SDK 7.0.133+; pin versions and retest upgrades whileexperimental_decideis experimental.Load the same
NEON_AI_GATEWAY_TOKENandNEON_AI_GATEWAY_BASE_URLused for embeddings; the provider handles the endpoint and credentials.The AI Gateway, for both Jev and embeddings, requires prepaid AI Gateway credits, available on every Neon plan, including Free. Without them, embed documents and queries with one model from another provider and use RRF.
import { neon } from "@neon/ai-sdk-provider";
import { experimental_decide as decide } from "ai";
type Candidate = { id: string; title: string; body: string };
async function rerankWithJev(
queryText: string,
candidates: Candidate[], // deduplicated, authorized rows in a stable order
limit = 10,
batchSize = 80,
): Promise<Candidate[]> {
if (!Number.isInteger(limit) || limit < 1) {
throw new Error("limit must be a positive integer");
}
if (!Number.isInteger(batchSize) || batchSize < 1) {
throw new Error("batchSize must be a positive integer");
}
if (candidates.length === 0) return [];
const model = neon.decisionModel("typesafeai-jev-1-14-0");
const criteria = {
true: "The candidate states the specific facts or steps the query asks for.",
false:
"The candidate only shares keywords or a topic with the query, answers a different question, or lacks the requested information.",
};
const abortSignal = AbortSignal.timeout(10_000); // whole reranking budget
const scored: { doc: Candidate; index: number; probability: number }[] = [];
for (let start = 0; start < candidates.length; start += batchSize) {
const batch = candidates.slice(start, start + batchSize);
const { answers } = await decide({
model,
state: { query: queryText }, // original text, without embedding instructions
questions: Object.fromEntries(
batch.map((doc, offset) => [
`d${start + offset}`, // response key only; the candidate goes in instructions
{
type: "boolean" as const,
instructions: {
question:
"Given the search query in state.query, does this candidate passage supply the specific information the user is looking for?",
candidate: { title: doc.title, body: doc.body },
},
criteria,
},
]),
),
maxRetries: 0, // propagate errors to the caller without retrying
abortSignal,
});
for (const [offset, doc] of batch.entries()) {
const index = start + offset;
const answer = answers[`d${index}`];
if (answer.type !== "boolean") {
throw new Error(`Missing relevance probability for d${index}`);
}
scored.push({ doc, index, probability: answer.probability });
}
}
return scored
.sort((a, b) => b.probability - a.probability || a.index - b.index)
.slice(0, limit)
.map(({ doc }) => doc);
}The SDK's boolean answer exposes the probability of yes as answer.probability (TypeSafe calls it noul). This is a probability that the passage answers the query, not a degree of completeness. Calibrate a threshold on judged no-match queries if the application must return "no answer."
batchSize = 80 matches the maximum candidate pool above. Each request must fit Jev 1.14's 65,536-token context window, including all candidate text and questions; reduce the batch size for longer passages. Tune the shared timeout to the request's latency budget.
The caller can catch reranking errors and use RRF as a fallback.
RRF Example
Use this query on its own when you want hybrid search without an additional model call.
For rank r and constant k, each retriever contributes 1 / (k + r). Start with a target of 40 candidates per retriever and k = 60; vector cutoff ties can exceed that target. Tune both for the corpus and workload.
Embed the query text with the same embedding model used for the stored documents, then bind that vector as $1, the original query text as $2, and the final result count as $3:
WITH vector_ranked AS (
SELECT id, RANK() OVER (ORDER BY distance) AS rank
FROM (
SELECT id, embedding <=> $1::vector AS distance
FROM documents
WHERE embedding IS NOT NULL
ORDER BY distance
FETCH FIRST 40 ROWS WITH TIES
) AS vector_candidates
),
keyword_ranked AS (
SELECT id, RANK() OVER (ORDER BY score) AS rank
FROM (
SELECT id, score
FROM (
SELECT
id,
body_tsv <@> to_bm25query(
to_tsvector('english', $2),
'documents_body_bm25'::regclass
) AS score
FROM documents
) AS keyword_scored
WHERE score < 0
ORDER BY score, id
LIMIT 40
) AS keyword_candidates
)
SELECT
d.id,
d.title,
COALESCE(1.0 / (60 + v.rank), 0) +
COALESCE(1.0 / (60 + k.rank), 0) AS rrf_score
FROM documents AS d
LEFT JOIN vector_ranked AS v ON v.id = d.id
LEFT JOIN keyword_ranked AS k ON k.id = d.id
WHERE v.id IS NOT NULL OR k.id IS NOT NULL
ORDER BY rrf_score DESC, d.id
LIMIT $3;score < 0 excludes BM25 non-matches. Many matching documents can share a BM25 score, so WITH TIES could admit a large group at the cutoff. ORDER BY score, id LIMIT 40 keeps keyword candidates bounded and breaks boundary ties by ID. RANK() uses score alone so retained ties receive equal ranks.
Vector retrieval preserves cutoff ties and can exceed 40 candidates. lakebase_bm25.default_limit defaults to 1000; the SQL limit bounds keyword rows entering fusion, not total scoring work.
Adapt the Hybrid Search
Retrieve more candidates from each source than the final result count; otherwise one retriever can dominate before fusion has enough overlap. Keep
lakebase_bm25.default_limitat least as large as the BM25 candidate target.Keep each retriever's operator and index configuration correct independently before tuning fusion or reranking.
Tune candidate counts and the RRF constant with judged or behavioral relevance data, plus latency measurements.
Compare vector-only, BM25-only, RRF-only, the deduplicated union plus Jev, and optional RRF plus Jev on the same judged queries to isolate each stage's contribution. Measure recall before reranking and nDCG@10 or MRR after it, alongside p95 latency, input-token cost, and fallback rate.
Add weights only when product evidence shows one retriever should contribute more. Weight the reciprocal-rank contributions, not the raw vector distance and negative BM25 score.
Apply the same access-control and tenant filters to both candidate CTEs. If BM25 filters are strict and cheap, evaluate whether
lakebase_bm25.prefilterimproves the filtered query.
Sources: Lakebase Search get-started guide and TypeSafe reranking cookbook.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs an MCP server, Needs network access, Needs Node.js
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- Neon
- Publisher
- Neon (Official)
- Source
- neondatabase/agent-skills · skills/neon-postgres · commit 2b0e2b6
- Licence
- Apache License 2.0 (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
- Also distributed in
- neondatabase/agent-skills
AutoGineer is not affiliated with or endorsed by Neon.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download neon-postgres.zip