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 runs | Step 1: files | Step 2: enable |
|---|---|---|
| Hosted platform (StitchDB and many others) | Already installed | Dashboard switch or create extension |
StitchDB local stack (stitchdb start) | Included in the local Postgres 17 | create extension |
| macOS with Homebrew Postgres | brew install pgvector | create extension |
| Ubuntu or Debian | sudo apt install postgresql-17-pgvector | create extension |
| Docker | pgvector/pgvector:pg17 image | create extension |
| Anything else | Build from source with make | create 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:
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:
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:
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):
npm install -g stitchdb-cli
stitchdb init
stitchdb startstitchdb 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:
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:
brew install pgvectorThe 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:
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:
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:
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:
cd /tmp
git clone --branch v0.8.7 https://github.com/pgvector/pgvector.git
cd pgvector
make
sudo make installmake 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
-- 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
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:
pip install "psycopg[binary]" pgvectorimport 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:
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().dataThat path applies Row Level Security for the signed-in user. The match_chunks function is in the pgvector RAG guide.
#Troubleshooting
| Error | Cause | Fix |
|---|---|---|
could not open extension control file ".../vector.control" | Files not installed for this Postgres version | Install the package for your exact major version, or set PG_CONFIG before make install |
type "vector" does not exist | Extension not enabled in this database, or it is in a schema not on your search_path | create extension vector; in this database, or set search_path = public, extensions |
permission denied to create extension "vector" | Your role cannot create extensions | Use the database owner role, or the hosted platform's dashboard |
expected 1536 dimensions, not 768 | Embedding size differs from the column | Use the same model everywhere, or change the column type |
Illegal instruction after copying a build | Compiled with -march=native on another CPU | Rebuild with make OPTFLAGS="" |
| Index not used | Operator does not match the index's operator class, or the table is tiny | Use <=> 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.