@prisma-next/extension-pgvector
PostgreSQL pgvector extension pack for Prisma Next.
Overview
This extension pack adds support for the vector data type and vector similarity operations (e.g., cosine distance) for PostgreSQL databases with the pgvector extension installed.
Responsibilities
- Vector Codec: Provides codec for
pg/vector@1 mapping to number[] at runtime, and a Vector<N> type for dimensioned typing in contract.d.ts
- Vector Operations: Registers vector similarity operations (e.g.,
cosineDistance) for use in queries
- CLI Integration: Provides extension descriptor for
prisma-next.config.ts configuration
- Runtime Extension: Registers codecs and operations at runtime for vector column operations
- Pack Ref Export: Ships a pure
/pack entrypoint for TypeScript contract authoring without runtime filesystem access
- Baseline Migration: Ships an on-disk baseline migration in its contract space that installs the
vector Postgres extension (CREATE EXTENSION IF NOT EXISTS vector) when the extension is composed into an application
Dependencies
@prisma-next/cli: CLI config types and extension descriptor interface
@prisma-next/sql-operations: SQL operation signature types
@prisma-next/sql-relational-core: Codec registry and AST types
arktype: Schema validation for manifest structure
Installation
pnpm add @prisma-next/extension-pgvector
Database Setup
The pgvector extension ships an on-disk baseline migration in its contract space; applying that migration installs pgvector with CREATE EXTENSION IF NOT EXISTS vector. When the extension is composed into an application via extensionPacks, prisma-next db init and prisma-next db update apply the baseline (and any subsequent migrations) automatically.
For manual database setup, the equivalent DDL is:
CREATE EXTENSION IF NOT EXISTS vector;
Ensure the baseline migration (or equivalent DDL) has been applied before running workloads that use vector columns.
Configuration
Add the extension to your prisma-next.config.ts:
import { defineConfig } from '@prisma-next/cli/config-types';
import postgresAdapter from '@prisma-next/adapter-postgres/control';
import sql from '@prisma-next/family-sql/control';
import postgres from '@prisma-next/target-postgres/control';
import pgvector from '@prisma-next/extension-pgvector/control';
export default defineConfig({
family: sql,
target: postgres,
adapter: postgresAdapter,
extensionPacks: [pgvector],
});
Usage
Contract Definition
Add vector columns to your contract and enable the namespace via pack refs:
import { int4Column, textColumn } from '@prisma-next/adapter-postgres/column-types';
import sqlFamily from '@prisma-next/family-sql/pack';
import { defineContract, field, model } from '@prisma-next/sql-contract-ts/contract-builder';
import { vector } from '@prisma-next/extension-pgvector/column-types';
import pgvector from '@prisma-next/extension-pgvector/pack';
import postgres from '@prisma-next/target-postgres/pack';
export const contract = defineContract({
family: sqlFamily,
target: postgres,
extensionPacks: { pgvector },
models: {
Post: model('Post', {
fields: {
id: field.column(int4Column).id(),
title: field.column(textColumn),
embedding: field.column(vector(1536)).optional(),
},
}).sql({ table: 'post' }),
},
});
The vector(N) factory is registered through the unified CodecDescriptor<{ length: number }> shape — paramsSchema validates the dimension at the contract boundary, renderOutputType: ({ length }) => 'Vector<' + length + '>' produces the column's TS type for contract.d.ts, and the curried factory materializes the runtime codec at context construction. See ADR 208 — Higher-order codecs for parameterized types for the descriptor model. Every pgvector column must declare an explicit dimension via vector(N); the runtime codec is constructed against { length: N }, so an undimensioned form has no honest descriptor signature.
Runtime Setup
Register the extension when creating your execution stack:
import { instantiateExecutionStack } from '@prisma-next/framework-components/execution';
import { createExecutionContext, createSqlExecutionStack } from '@prisma-next/sql-runtime';
import postgresAdapter from '@prisma-next/adapter-postgres/runtime';
import postgresTarget from '@prisma-next/target-postgres/runtime';
import pgvector from '@prisma-next/extension-pgvector/runtime';
const stack = createSqlExecutionStack({
target: postgresTarget,
adapter: postgresAdapter,
extensionPacks: [pgvector],
});
const context = createExecutionContext({ contract, stack });
const stackInstance = instantiateExecutionStack(stack);
Query Usage
Use vector similarity operations in your queries:
import { sql, tables } from '../prisma/query';
import { param } from '@prisma-next/sql-query/param';
import type { ResultType } from '@prisma-next/sql-query/types';
const queryVector = [0.1, 0.2, 0.3, ];
const plan = sql
.from(tables.post)
.select({
id: tables.post.columns.id,
title: tables.post.columns.title,
distance: tables.post.columns.embedding.cosineDistance(param('queryVector')),
})
.orderBy(tables.post.columns.embedding.cosineDistance(param('queryVector')).asc())
.limit(10)
.build({ params: { queryVector } });
type Row = ResultType<typeof plan>;
Types
Codec Types
The extension provides:
CodecTypes mapping the pg/vector@1 type ID to number[] (runtime representation)
Vector<N> type for dimensioned vector typing in emitted contract.d.ts and schema result types when the contract includes dimension metadata
import type { CodecTypes, Vector } from '@prisma-next/extension-pgvector/codec-types';
Operation Types
The extension provides an OperationTypes export for vector operations:
import type { OperationTypes } from '@prisma-next/extension-pgvector/operation-types';
Operations
cosineDistance
Computes the cosine distance between two vectors.
Signature: cosineDistance(rhs: number[] | vector): number
SQL: Uses the pgvector <=> operator: vector1 <=> vector2
Example:
const distance = tables.post.columns.embedding.cosineDistance(param('queryVector'));
cosineSimilarity
Computes the cosine similarity between two vectors (1 minus cosine distance).
Signature: cosineSimilarity(rhs: number[] | vector): number
SQL: Uses the pgvector <=> operator: 1 - (vector1 <=> vector2)
Example:
const similarity = tables.post.columns.embedding.cosineSimilarity(param('queryVector'));
Capabilities
The extension declares the following capabilities:
pgvector.cosine: Indicates support for cosine distance and similarity operations
Authoring (maintainers)
After changing the contract source, run pnpm migrations:regen from the repo root to keep migration metadata, refs/head.json, and end-contract.* consistent with the freshly-built src/contract.json; it is also wired into pnpm fixtures:emit automatically.
See ADR 212 — Contract spaces ("Contract-space package layout") for the layout and rationale.
References
Pack refs (@prisma-next/extension-pgvector/pack) are pure data objects generated from the hydrated manifest (src/core/manifest.ts), so TypeScript contract builders can enable the pgvector namespace in both emit and no-emit workflows without touching the filesystem.