How to Install pgvector (Hosted, Local, Docker, Python)

To install pgvector you do two things: put the extension's files on the Postgres server (a package such as postgresql-17-pgvector, brew install pgvector, the pgvector/pgvector Docker image, or a build from source), then run create extension vector; once in each database that needs it. On most hosted Postgres platforms the first step is already done, so you only run the SQL or flip a switch in the dashboard. This guide covers each environment, how to check it worked, a first query, Python usage, and fixes for the errors people hit most.

#How to install pgvector: pick your path

Where your Postgres runsStep 1: filesStep 2: enable
Hosted platform (StitchDB and many others)Already installedDashboard switch or create extension
StitchDB local stack (stitchdb start)Included in the local Postgres 17create extension
macOS with Homebrew Postgresbrew install pgvectorcreate extension
Ubuntu or Debiansudo apt install postgresql-17-pgvectorcreate extension
Dockerpgvector/pgvector:pg17 imagecreate extension
Anything elseBuild from source with makecreate extension

pgvector supports Postgres 13 and newer. The current release at the time of writing is 0.8.7.

#Hosted Postgres

If you use a managed Postgres, do not try to compile anything: you cannot reach the server's file system, and you do not need to. Check whether the extension is offered:

SQL
select name, default_version, installed_version
from pg_available_extensions
where name = 'vector';

A row with a default_version means you can enable it. If installed_version is already filled in, it is on.

#On StitchDB

In Studio open Database → Extensions, search for vector and switch it on. Or run this in the SQL Editor:

SQL
create extension if not exists vector with schema extensions;

StitchDB puts most extensions in the extensions schema rather than public (docs), so the type is extensions.vector. That keeps the extension's many functions and operators out of your API schema. You will see it qualified in table definitions:

SQL
create table public.documents (
  id bigint generated always as identity primary key,
  content text,
  embedding extensions.vector(1536)
);

The extension is available on every plan, including Free.

#Local development with the StitchDB CLI

If you want the same setup on your laptop, the StitchDB CLI runs Postgres 17 with common extensions, pgvector included, as plain processes (no Docker):

Terminal
npm install -g stitchdb-cli
stitchdb init
stitchdb start

stitchdb start prints the local URLs; Postgres listens on postgresql://postgres:[email protected]:54322/postgres. Put the create extension statement in a migration so it runs the same way locally and on your hosted project:

Terminal
stitchdb migration new enable_vector
# add: create extension if not exists vector with schema extensions;
stitchdb migration up     # local database
stitchdb db push          # linked project

#macOS (Homebrew)

With Postgres installed through Homebrew:

Terminal
brew install pgvector

The pgvector README notes this adds it to the postgresql@18 and postgresql@17 formulas. If you use another Postgres on your Mac, such as Postgres.app, check its docs: Postgres.app ships with pgvector included.

Then connect and enable it:

Terminal
psql postgres -c 'create extension vector;'

#Ubuntu and Debian (APT)

Packages come from the PostgreSQL APT repository (apt.postgresql.org). After you have added it, install the package that matches your server's major version:

Terminal
sudo apt install postgresql-17-pgvector
sudo -u postgres psql -d mydb -c 'create extension vector;'

Replace 17 with your version (psql -c 'show server_version;' tells you). Installing the wrong major version is the most common reason create extension still fails after "installing" pgvector.

On RHEL, Fedora and similar systems, the PostgreSQL Yum repository has pgvector_17 (sudo dnf install pgvector_17).

#Docker

The official image is the Postgres image with pgvector added:

Terminal
docker run -d --name pg \
  -e POSTGRES_PASSWORD=secret \
  -p 5432:5432 \
  pgvector/pgvector:pg17

docker exec -it pg psql -U postgres -c 'create extension vector;'

Tags exist for Postgres 13 through 18 (pg13 ... pg18, plus versioned tags such as 0.8.7-pg17). If you raise maintenance_work_mem for faster HNSW builds, give the container at least that much shared memory with --shm-size, or parallel index builds can fail.

#From source

For any Linux or macOS server where no package fits:

Terminal
cd /tmp
git clone --branch v0.8.7 https://github.com/pgvector/pgvector.git
cd pgvector
make
sudo make install

make uses pg_config to find your Postgres. If you have several versions, point it at the right one with export PG_CONFIG=/usr/lib/postgresql/17/bin/pg_config first. A postgres.h: No such file or directory error means the server development headers are missing: install postgresql-server-dev-17 on Debian or Ubuntu. On Windows, pgvector builds with nmake from the Visual Studio x64 Native Tools prompt.

#Verify the installation

SQL
-- Which version is enabled in this database?
select extversion from pg_extension where extname = 'vector';

-- Does the type work?
select '[1,2,3]'::vector <-> '[4,5,6]'::vector as l2_distance;

The second query should return about 5.196. The version matters: HNSW indexes need 0.5.0, halfvec, sparsevec and binary quantization need 0.7.0, and iterative index scans for filtered queries need 0.8.0.

Remember that extensions are per database. If you created a new database, enable pgvector again there.

#Your first table, index and query

SQL
create table items (
  id bigserial primary key,
  label text,
  embedding vector(3)
);

insert into items (label, embedding) values
  ('a', '[1,2,3]'),
  ('b', '[4,5,6]'),
  ('c', '[1,1,1]');

create index on items using hnsw (embedding vector_cosine_ops);

select label, embedding <=> '[1,2,2]' as cosine_distance
from items
order by embedding <=> '[1,2,2]'
limit 2;

Real embeddings have hundreds or thousands of dimensions; set vector(n) to your model's output size. With pgvector in the extensions schema (as on StitchDB), either qualify names (extensions.vector(3), extensions.vector_cosine_ops) or run set search_path = public, extensions; first. On a tiny table, Postgres may skip the index and scan; that is expected.

#Using pgvector from Python

Install the driver and the pgvector adapter:

Terminal
pip install "psycopg[binary]" pgvector
python
import os
import psycopg
from pgvector import Vector
from pgvector.psycopg import register_vector

# Session mode (port 5432) keeps SET for the whole connection
conn = psycopg.connect(os.environ["DATABASE_URL"], autocommit=True)

# The vector type lives in the extensions schema on StitchDB
conn.execute("set search_path = public, extensions")
register_vector(conn)

embedding = Vector([0.12, -0.03, 0.88])
conn.execute("insert into items (label, embedding) values (%s, %s)", ("d", embedding))

rows = conn.execute(
    "select label from items order by embedding <=> %s limit 5",
    (embedding,),
).fetchall()
print(rows)

register_vector looks up the vector type, which is why the search_path line comes first; without it you get "vector type not found in the database". For a StitchDB project, copy the connection string from Settings → Database, use port 5432, and keep sslmode=require (connection docs). The pooler ignores startup options such as search_path in the connection string, so set it with SQL after connecting.

If your Python code runs in a web app rather than a script, you may not need a direct connection at all: put the similarity query in a SQL function and call it through the API with the Python SDK:

python
from stitchdb import create_client

stitchdb = create_client(os.environ["STITCHDB_URL"], os.environ["STITCHDB_KEY"])
matches = stitchdb.rpc("match_chunks", {"query_embedding": embedding_list, "match_count": 5}).execute().data

That path applies Row Level Security for the signed-in user. The match_chunks function is in the pgvector RAG guide.

#Troubleshooting

ErrorCauseFix
could not open extension control file ".../vector.control"Files not installed for this Postgres versionInstall the package for your exact major version, or set PG_CONFIG before make install
type "vector" does not existExtension not enabled in this database, or it is in a schema not on your search_pathcreate extension vector; in this database, or set search_path = public, extensions
permission denied to create extension "vector"Your role cannot create extensionsUse the database owner role, or the hosted platform's dashboard
expected 1536 dimensions, not 768Embedding size differs from the columnUse the same model everywhere, or change the column type
Illegal instruction after copying a buildCompiled with -march=native on another CPURebuild with make OPTFLAGS=""
Index not usedOperator does not match the index's operator class, or the table is tinyUse <=> with vector_cosine_ops, <-> with vector_l2_ops, <#> with vector_ip_ops

To upgrade on a server you manage, install the new files and run alter extension vector update; in each database.

#FAQ

#Is pgvector free?

Yes. It is open source under the PostgreSQL License. You only pay for the Postgres server it runs on.

#Do I need to restart Postgres after installing pgvector?

No. pgvector does not need to be preloaded. Install the files, then run create extension vector;.

#Which Postgres versions does pgvector support?

Postgres 13 and newer. Use the package or Docker tag that matches your server's major version.

#How do I use pgvector with Python?

Install pgvector and a driver such as psycopg 3, call register_vector(conn) after connecting, and pass Vector objects or lists as query parameters.

#Can I use pgvector with SQLAlchemy or Django?

Yes. The pgvector-python package includes integrations for SQLAlchemy, SQLModel, Django and other Python libraries.

Get pgvector without installing anything: create a free project and switch on vector under Database → Extensions.