Using extensions
Extensions add database capabilities like vector search, geospatial data, and full-text search to a Prisma ORM project.
An extension is a package that adds a database capability Prisma ORM does not have out of the box: new column types, query operations, and index types, along with the migrations that install the underlying database feature. Vector search, geospatial data, full-text search, typed JSON, and provider-specific integrations are all added through extensions.
Use an extension when you need one of these database features while keeping typed schema declarations, generated TypeScript, migration support, and query helpers in your Prisma ORM project.
To add an extension, install its package and register it in two places: the config and the client. The steps below use pgvector, the vector search extension, as the example. Supabase is wired differently; see the note on the catalog.
1. Install the package
bun add @prisma/orm-extension-pgvector2. Register it in the config
Prisma ORM uses this registration when it emits your contract and plans migrations:
import { definePrismaConfig } from 'prisma/config';
import pgvector from '@prisma/orm-extension-pgvector/control';
import { defineConfig as ormConfig } from '@prisma/orm-postgres/config';
export default definePrismaConfig({
orm: ormConfig({
contract: './src/prisma/contract.prisma',
extensions: [pgvector],
db: {
connection: process.env['DATABASE_URL']!,
},
}),
});3. Register it on the client
Prisma ORM uses this registration when your app runs queries: it adds the extension's query operations and value types:
import pgvector from '@prisma/orm-extension-pgvector/runtime';
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };
export const db = postgres<Contract>({
contractJson,
url: process.env['DATABASE_URL']!,
extensions: [pgvector],
});4. Use the new type in your schema
The extension's types are now available in your contract. Declare a vector column with an explicit dimension:
types {
Embedding1536 = pgvector.Vector(1536)
}
model Post {
id String @id @default(uuid())
title String
embedding Embedding1536?
}5. Apply and query
Run npx prisma@latest db init (or db update on an existing database). The extension ships its own migration, so this step runs CREATE EXTENSION IF NOT EXISTS vector for you. If db init reports a contract-space layout violation instead, run npx prisma@latest migration plan once: it writes the extension's baseline migration under migrations/<extension>/, and db init then proceeds. Then query with the operations the extension adds:
const plan = db.sql.public.post
.select('id', 'title')
.select('distance', (f, fns) => fns.cosineDistance(f.embedding, queryVector))
.orderBy((f, fns) => fns.cosineDistance(f.embedding, queryVector), { direction: 'asc' })
.limit(10)
.build();
const similar = await db.runtime().query(plan);pgvector contributes fns.cosineSimilarity alongside fns.cosineDistance. Both take two vector expressions and return a float8; similarity sorts descending where distance sorts ascending.
How the pieces fit
One package, two registrations, one database:
Capabilities
Each extension names what it adds under a key like pgvector.cosine. You never write these keys by hand. Registering the extension in the config records them in your contract. Registering it in db.ts provides them at runtime.
The point of this bookkeeping is to fail early:
- If your contract needs an extension that
db.tsdoes not register, creating the client fails immediately. A query never runs with the extension only partially registered. - If the database itself cannot install the extension,
db initordb updatereports it before your app takes traffic.
Available extensions
Every extension, by Prisma and by the community, is listed in the extension directory with install commands and registration snippets. The table below is generated from the same registry.
| Name | What it adds | Package | Databases | By |
|---|---|---|---|---|
| arktype-json | JSON columns validated by an arktype schema and typed end to end. | @prisma/orm-extension-arktype-json | PostgreSQL | Prisma |
| MongoDB | MongoDB support for Prisma ORM: config, runtime, contract authoring, BSON values, and migrations in one package. | @prisma/orm-mongo | MongoDB | Prisma |
| ParadeDB (experimental) | BM25 full-text search indexes. | @prisma/orm-extension-paradedb | PostgreSQL | Prisma |
| pgvector | Vector columns and similarity search for embeddings. | @prisma/orm-extension-pgvector | PostgreSQL | Prisma |
| PostGIS | Geometry columns and geospatial queries such as distance and containment. | @prisma/orm-extension-postgis | PostgreSQL | Prisma |
| PostgreSQL | PostgreSQL support for Prisma ORM: config, runtime, contract authoring, and migrations in one package. | @prisma/orm-postgres | PostgreSQL | Prisma |
| SQLite (experimental) | SQLite support for Prisma ORM: config, runtime, contract authoring, and migrations in one package. | @prisma/orm-sqlite | SQLite | Prisma |
| Supabase (experimental) | Supabase auth and storage tables plus role-bound clients for row-level security. | @prisma/orm-extension-supabase | PostgreSQL | Prisma |
| IndexedDB (experimental) | Prisma 8 for IndexedDB: a browser database from your PSL schema, with typed accessors and explicit migrations. | @prisma-next-idb/client-idb | IndexedDB | Prisma IDB |
| typed-json | Typed JSON and text columns with no validator dependency. | prisma-orm-extension-typed-json | PostgreSQL | Omar Dulaimi |
| zod-json | Typed JSON columns described and enforced by a zod schema. | prisma-orm-extension-zod-json | PostgreSQL | Omar Dulaimi |
The database packages are extensions too: @prisma/orm-postgres, @prisma/orm-sqlite, and @prisma/orm-mongo plug the SQL and document families into the same core, which is how a community package can add another database. Experimental extensions work but their surface is still moving: ParadeDB supports the key_field index option only so far, and SQLite is published but not yet covered by a quickstart. Names link to each extension's directory page, which links on to the package README. Middleware is listed on How middleware works.
Supabase ships no /control subpath. Import its pack from @prisma/orm-extension-supabase/pack instead and pass it to the same ormConfig({ extensions: [supabasePack] }) call the recipe above uses. The client is where the wiring differs: build it with the supabase() factory from @prisma/orm-extension-supabase/runtime rather than postgres(). That factory is role-first (asUser(jwt), asAnon(), asServiceRole()) and carries the JWT validation and RLS binding. See the runnable example for the whole wiring.
For a working project per extension, see the runnable examples: pgvector, PostGIS, ParadeDB, and Supabase.
You can build an extension that does not exist yet. Extension packs are versioned npm packages with a documented layout; the call for extension authors explains how to write and publish one. When it is on npm, submit it to the directory: the form validates the entry and opens the pull request for you.
See also
- Advanced queries: the SQL query builder, where extension operations like
cosineDistanceappear - How middleware works for wrapping queries rather than adding database capabilities
- Quickstart with PostgreSQL to set up a project to add extensions to
- Extensions overview for the full catalog, including middleware
- Prisma ORM overview for the contract-first model extensions plug into
