dbForge Studio for PostgreSQL
AI-powered IDE for database development, management, and data analysis across PostgreSQL and related cloud services
In this guide, we explore pgvector, the answer to developers' growing demand for a practical way to store and search vector embeddings alongside the application data they already manage. pgvector brings vector similarity search directly to PostgreSQL, allowing teams to store embeddings, compare vectors, and build semantic search and AI-powered features without introducing a separate vector database. This guide walks through the basics of pgvector: what it is, how it works, how to install and enable it, and how to store, search, and filter embeddings using familiar SQL.
A popular developer tool, pgvector is an open-source PostgreSQL extension that adds support for storing vector embeddings and performing vector similarity searches directly in PostgreSQL. In simple terms, it allows PostgreSQL to work with numerical representations of text, images, and other data that AI and machine learning models use to capture meaning and relationships.
This makes pgvector useful for building AI-powered search, semantic search, recommendation systems, and Retrieval-Augmented Generation (RAG) applications. Instead of keeping embeddings in a separate vector database, you can store them alongside your existing relational data in PostgreSQL. For example, a product catalog can contain product details and their embeddings in the same database, making it easier to combine traditional SQL queries with similarity search.
One of the main advantages of pgvector is that developers can use PostgreSQL as both a traditional relational database and a vector store. Instead of introducing a separate vector database from the beginning, teams can keep their application data and AI-related embeddings in the same PostgreSQL database. This can simplify the architecture, reduce the number of systems to maintain, and make it easier to combine vector similarity search with familiar SQL queries and relational data.
This approach is useful for many AI-powered applications. Developers can use pgvector to find documents that are semantically similar to a user's question, recommend related products, match user queries with relevant stored content, or provide the retrieval layer for AI assistants and RAG applications. For teams that already use PostgreSQL, pgvector provides a practical way to add vector search capabilities while continuing to work with the database and tools they already know.
Traditional PostgreSQL search and pgvector solve different search problems. PostgreSQL full-text search is primarily based on words and language patterns. It can tokenize text, account for variations of words, and rank results based on how well the search terms match the content. This makes it a good choice when users know the words or phrases they are looking for.
In its turn, pgvector enables vector similarity search, which works with numerical embeddings generated by AI models. These embeddings represent the meaning or semantic characteristics of content, allowing PostgreSQL to find items that are conceptually similar even when they do not contain the exact search terms.
For example, if you are searching for "ways to reduce car fuel consumption", a traditional keyword search may prioritize documents containing words such as "car", "fuel", and "consumption", but it may miss a relevant article that talks about "improving vehicle mileage" without using those exact terms. A vector search can recognize that the concepts are related and return the article based on semantic similarity.
In practice, the two approaches can complement each other.
Most modern configurations implement a hybrid search model, where you can run a keyword search alongside a vector search. Such a method takes advantage of both approaches: keyword search provides precision, while vector search provides semantic relevance. For PostgreSQL applications, the hybrid model also allows developers to combine existing full-text search capabilities with pgvector rather than choosing one method exclusively.
The basic pgvector search workflow consists of four steps.
Vector embeddings are numerical representations of content that capture its semantic meaning. Instead of representing text as individual words, an embedding model converts a piece of content—such as a sentence, paragraph, document, or image—into a vector: an ordered list of numbers that describes its meaning in a high-dimensional space.
For text search, each document or text chunk is converted into its own embedding. When a user submits a query, the same embedding model converts the query into another vector. Rather than looking for exact keyword matches, pgvector compares these vectors to identify content with similar meanings. As a result, documents discussing the same concept tend to produce vectors that are close together, even if they use different words or phrases.
For example, these two sentences have a similar meaning; however, they use different wording.
A keyword search may regard these sentences as quite different because they share few exact terms. An embedding model, however, is likely to generate vectors that are close to one another because the underlying meaning is similar.
The size of a vector is called its dimension. Modern embedding models commonly produce vectors with 768, 1024, 1536, or greater dimensions, depending on the model being used. The dimension is determined by the embedding model itself and must be consistent for all vectors stored in a given column. Because different AI providers and open-source models use different dimensions, it is best to design applications around the embedding model's requirements rather than assuming a single standard size.
One of pgvector's biggest advantages is that it lets you store vector embeddings alongside your existing relational data in PostgreSQL. Instead of maintaining a separate vector database, you can keep AI-generated embeddings together with the structured business data that describes them.
For example, you can include a vector column in a standard PostgreSQL table together with usual columns.
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
title TEXT,
category TEXT,
url TEXT,
content TEXT,
created_at TIMESTAMP,
tenant_id INTEGER,
metadata JSONB,
embedding VECTOR(1536)
);
Keeping vector and relational data together makes it easy to combine semantic search with traditional SQL filtering. For example, an application can search for documents that are semantically similar to a user's query while also filtering by category, publication date, tenant, or any other business attribute.
This is one of pgvector's strongest use cases. Rather than managing separate systems for structured data and vector data, you can store everything in PostgreSQL and use familiar SQL features—including JOINs, filters, aggregates, transactions, and access controls—alongside vector similarity search. The result is a simpler architecture that keeps AI-powered search closely integrated with the application's core business data.
Getting started with pgvector involves two main steps: installing the extension on your PostgreSQL server and enabling it in the database where you want to use PostgreSQL vector search. The exact installation method depends on how PostgreSQL is deployed, but the overall workflow is the same.
If you're using PostgreSQL in Docker, the easiest approach is to use a PostgreSQL image that already includes pgvector or build your own image with the extension installed.
Docker is a popular option for local development because it provides a consistent environment without requiring manual installation on the host machine.
For PostgreSQL installed directly on a server, pgvector can typically be installed using your operating system's package manager or by compiling it from source if a package is not available.
Many managed PostgreSQL services also support pgvector. Depending on the provider, the extension may already be installed or available as an option you can enable for your database. Check your cloud provider's documentation to confirm availability and any version requirements.
After pgvector is installed on the PostgreSQL server, it must be enabled in each database where you want to use it. To enable pgvector, run the following command.
CREATE EXTENSION IF NOT EXISTS vector;
In PostgreSQL, the extension is registered under the name vector. To verify that the extension is enabled and available, execute the following query.
SELECT extname, extversion
FROM pg_extension
WHERE extname = 'vector';
If the result contains a row with the vector extension, pgvector is ready to use in the database.
With the pgvector PostgreSQL extension enabled, you can create a table that includes a column of type vector, alongside any regular columns your application needs. Just use the standard CREATE TABLE statement, adding the embedding column.
CREATE TABLE documents (
id BIGSERIAL PRIMARY KEY,
title TEXT,
content TEXT,
embedding VECTOR(1536)
);
Here, 1536 is the vector's dimension—the number of values each embedding contains. This number must match the output size of the embedding model you plan to use; a mismatch between the table definition and the vectors you insert will cause errors.
The vector dimension is the number of values in an embedding. Different embedding models produce vectors with different dimensions—for example, one model may return 768-dimensional vectors while another may return 1536-dimensional vectors. There is no single dimension that is correct for every application; the appropriate size depends on the embedding model you choose.
When using pgvector, the dimension defined for the PostgreSQL column must match the vectors generated by the model. If your embedding model produces vectors with a different number of dimensions, those vectors cannot be inserted into the column.
Therefore, choose the embedding model before defining the vector column, and make sure the same model—or a compatible model with the same dimension—is used consistently for your stored content and search queries. Changing models later may require generating new embeddings and potentially changing or recreating the vector column and its indexes.
Essentially, pgvector provides the vector data type or the halfvec data type and similarity-search capabilities, but it does not generate embeddings itself. Embeddings are normally created by an external AI model or by application code using an embedding API or machine learning library. The resulting numerical vector is then inserted into a PostgreSQL table alongside the original content and any relevant metadata.
For example, a table might store a document and its embedding as a 3-dimensional vector as follows.
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
content TEXT,
embedding VECTOR(3)
);
An application can then insert an embedding into the embedding column.
INSERT INTO documents (content, embedding)
VALUES (
'PostgreSQL supports vector search.',
'[0.12, 0.45, 0.78]'
);
A small 3-dimensional vector such as [0.12, 0.45, 0.78], which we used in the example above, is useful for learning because it makes the examples easy to read and understand. You can manually insert values like these to experiment with pgvector's data type and similarity operators. In a real application, however, embeddings typically have much higher dimensions and are generated automatically from the content. For example, an application might send a document or text chunk to an embedding model, receive a vector containing hundreds or thousands of numerical values, and then store that vector in PostgreSQL.
In its turn, pgvector handles the storage and comparison of the resulting vectors; the embedding model is responsible for turning the original content into a numerical representation. This separation allows developers to choose an embedding model appropriate for their application while using PostgreSQL and pgvector to store and search the resulting embeddings.
Once embeddings are stored in PostgreSQL, pgvector can find the records whose vectors are closest to the query vector. The basic pattern is to use a pgvector distance operator in the ORDER BY clause and then limit the number of rows in the result to only return the closest matches.
SELECT id, title
FROM documents
ORDER BY embedding <=> '[0.1, 0.2, 0.3]'
LIMIT 5;
Here, the <=> operator calculates the distance between each stored embedding and the vector you are searching for. Rows with a lower distance value are considered closer matches, so ordering by distance and limiting the result set is what surfaces the most relevant rows first.
To calculate distances, pgvector supports several distance operators, allowing developers to choose how similarity should be measured.
| Operator | Meaning | Best use |
|---|---|---|
| <-> | Euclidean distance | General vector search |
| <#> | Negative inner product | Normalized vectors |
| <=> | Cosine distance | Text embeddings |
| <+> | L1 distance | Specific distance-based cases |
The example above uses <=>, which calculates cosine distance. It focuses on the direction of the vectors rather than their absolute magnitude. The important point is that the operator determines what "similar" means for the search, so the distance metric should be chosen to match the characteristics of the embeddings and the requirements of the application.
In real applications, vector similarity is rarely the only condition used to find relevant records. PostgreSQL can combine pgvector similarity search with regular SQL filters, allowing applications to search for semantically similar content while restricting the results to records that meet specific business or access rules. The example below shows how pgvector search can be used together with SQL filters.
SELECT id, title
FROM documents
WHERE category = 'docs'
ORDER BY embedding <=> '[0.1, 0.2, 0.3]'
LIMIT 5;
Here, PostgreSQL first limits the search to documents where category = 'docs', then orders those records by their vector distance and returns the five closest matches. This is useful when semantic relevance needs to be combined with structured information.
Common filters include:
Such combined search is one of the practical strengths of using pgvector with PostgreSQL. A query can use semantic similarity to determine relevance while standard SQL conditions enforce the application's business, security, and data-access rules.
By default, pgvector can perform an exact nearest-neighbor search, comparing the query vector with the stored vectors and returning the closest matches. This provides accurate results, but as the number of vectors grows, comparing every stored vector can become increasingly expensive.
For larger datasets, pgvector supports approximate nearest-neighbor indexes that reduce the amount of work required to find similar vectors. The two main ones are HNSW and IVFFlat. Both can significantly improve search performance, but they make different trade-offs between speed, memory usage, index-building time, and search accuracy.
HNSW (Hierarchical Navigable Small World) builds a graph structure that helps PostgreSQL navigate toward nearby vectors without comparing every vector. pgvector HNSW index is often a good choice when high search performance and strong recall are important. It generally provides a good balance between search speed and result quality, but it can require more memory and may take longer to build than some alternatives.
IVFFlat (Inverted File with Flat Compression) divides vectors into groups, or lists, and searches only selected groups rather than the entire dataset. IVFFlat can be useful when index size, build time, or resource usage needs to be controlled. Its performance depends more heavily on configuration, particularly the number of lists and how many lists are searched. The index generally needs to be built after representative data has been loaded so that the vector distribution can be properly captured.
| Index | Best for | Notes |
|---|---|---|
| HNSW | Faster search and strong recall | Good default for many use cases, but uses more memory |
| IVFFlat | Large datasets with faster index build | Should be created after data is loaded |
As vector datasets grow, it is useful to check pgvector similarity search execution with an EXPLAIN (ANALYZE, BUFFERS) query. EXPLAIN ANALYZE shows the actual execution plan and timing, while BUFFERS provides additional information about how much data PostgreSQL reads from memory and disk.
EXPLAIN (ANALYZE, BUFFERS)
SELECT *
FROM documents
ORDER BY embedding <=> '[0.1, 0.2, 0.3]'
LIMIT 5;
A sample execution plan looks as follows.
Limit (cost=12.45..13.02 rows=5 width=548)
(actual time=0.182..0.214 rows=5 loops=1)
Buffers: shared hit=42
-> Index Scan using documents_embedding_hnsw_idx on documents
(cost=12.45..11345.67 rows=100000 width=548)
(actual time=0.181..0.212 rows=5 loops=1)
Order By: (embedding <=> '[0.1,0.2,0.3]'::vector)
Buffers: shared hit=42
Planning Time: 0.145 ms
Execution Time: 0.247 ms
The execution plan can help determine whether PostgreSQL is using an appropriate access method and how much work is required to return the results. When reviewing a vector search plan, pay attention to the execution time, the number of rows processed, and whether an expected vector index is actually being used.
Common performance issues:
For many projects, pgvector is a strong option, but it is not the only way to add vector search to an application. For applications that require extremely large collections of embeddings, very high query throughput, or specialized optimization for large-scale AI workloads, dedicated vector databases may be a better fit.
Dedicated vector databases are database systems designed specifically for storing, indexing, and searching vector embeddings at scale. Unlike traditional relational databases, which are optimized for structured data and SQL operations, vector databases focus on performing fast nearest-neighbor searches across millions or even billions of high-dimensional vectors.
The table below compares pgvector with dedicated vector databases across the factors that typically matter most when choosing between them.
| Criteria | pgvector | Dedicated vector databases |
|---|---|---|
| Best fit | Teams already using PostgreSQL and wanting to add vector search without another database | Teams building large-scale AI search, RAG, recommendation, or semantic search systems |
| Data size | Small to medium vector datasets | Very large vector datasets with millions or billions of embeddings |
| Architecture | Runs inside PostgreSQL as an extension | Separate database built specifically for vector search |
| Main advantage | Keeps vector embeddings and relational data in one place | Better scalability, search speed, and vector-native features |
| Relational filtering | Strong option when vectors need to be filtered by users, categories, permissions, dates, or other SQL data | Supported, but metadata filtering depends on the specific vector database |
| Semantic search | Good for simple and moderate semantic search use cases | Better for complex, high-volume semantic search workloads |
| Hybrid search | Possible, but may require more manual setup with PostgreSQL full-text search | Often has built-in or more advanced hybrid search capabilities |
| Indexing | Supports vector indexes such as HNSW and IVFFlat | Usually offers advanced ANN indexing optimized for vector workloads |
| Scaling | Scales with PostgreSQL infrastructure | Designed for separate and distributed vector search scaling |
| Operations | Easier if the team already manages PostgreSQL | Requires managing or paying for an additional database/service |
| Prototyping | Very good for MVPs, internal tools, and early AI features | Useful when the project already expects high search volume or complex vector workloads |
| When it is enough | Small to medium datasets, simple semantic search, prototypes, internal tools, and apps where SQL filtering matters | Not usually necessary unless vector search becomes a major performance or scale requirement |
| When to choose the alternative | When PostgreSQL becomes a bottleneck for vector search performance, filtering, or scaling | When you need large-scale vector search, distributed architecture, advanced hybrid search, or independent scaling |
Getting started with pgvector follows a straightforward path: install the extension, enable it inside your database, create a table with a vector column, insert your embeddings, and run similarity search using pgvector's distance operators. As your dataset grows, adding an index such as HNSW or IVFFlat and keeping an eye on query performance with EXPLAIN ANALYZE will help you keep searches fast.
If you are working with PostgreSQL and pgvector, try dbForge Studio, a multi-feature IDE for PostgreSQL that can make everyday tasks easier—from writing and testing SQL queries to inspecting tables, editing data, and reviewing how your PostgreSQL workflows perform.
Basically, pgvector is an open-source PostgreSQL extension that adds a vector data type and vector similarity search directly to a PostgreSQL database. It lets you store embeddings alongside your regular relational data and query them using distance operators instead of running a separate vector database.
There are several ways to install pgvector depending on your environment: using a Docker image that already includes the extension, installing it through your operating system's package manager, or choosing a managed PostgreSQL provider or cloud service that offers pgvector out of the box. After installation, the extension still needs to be enabled inside the target database.
Once pgvector is installed on the server, you enable it in a specific database by running the CREATE EXTENSION IF NOT EXISTS vector; command.
This command only needs to run once
per database and makes the vector data type and related operators available for use.
Embeddings are stored in a regular PostgreSQL table using a column of type vector, with a fixed dimension that matches the output of the embedding model you use, for example, VECTOR(1536). The embeddings themselves are generated outside PostgreSQL, usually by an embedding model or API, and inserted into the table together with related data such as title, content, or category.
The right operator depends on how your embeddings were generated.
Check the documentation for the embedding model you use, since some models are optimized for a particular distance metric.
HNSW and IVFFlat are two index types available in pgvector. HNSW usually offers faster search and stronger recall and is a good default for many use cases, though it uses more memory. IVFFlat is often a better fit for large datasets since it builds faster, but it should be created only after the data is already loaded into the table.
Yes, pgvector is well suited for semantic search, especially for simple to moderate workloads where PostgreSQL already stores the related data. Because vector similarity search compares the meaning behind the content rather than exact keywords, it can return conceptually similar results even when the wording differs.
A dedicated vector database is worth considering when PostgreSQL is no longer sufficient for vector search performance, filtering, or scaling, or when a project needs very large-scale vector search, distributed architecture, or advanced hybrid search capabilities. For small to medium datasets, prototypes, and cases where SQL filtering matters, pgvector is often enough.