Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Pgvector Laravel Package

ankane/pgvector

Ruby gem for pgvector, the Postgres extension for vector similarity search. Adds vector columns, cosine/L2/inner product distance queries, and HNSW/IVFFlat index support to ActiveRecord, making it easy to build semantic search and AI-powered features on Postgres.

Deep Wiki
Context7

Getting Started

ankane/pgvector is a Ruby gem, but the core value is the Postgres vector extension, which is language-agnostic. In Laravel you leverage it through PostgreSQL and PDO rather than the gem itself.

Minimal setup:

  1. Use a Postgres image/server with pgvector available, e.g. pgvector/pgvector:pg16 locally, or a managed Postgres that supports the extension.
  2. Enable the extension in a migration:
    DB::statement('CREATE EXTENSION IF NOT EXISTS vector');
    
  3. Add a vector column:
    Schema::table('documents', function (Blueprint $table) {
        $table->vector('embedding', 1536)->nullable();
    });
    
    If your Laravel schema builder lacks vector(), use:
    DB::statement('ALTER TABLE documents ADD COLUMN embedding vector(1536)');
    
  4. Install a PHP vector helper such as pgvector/pgvector for formatting/parsing, or build a small cast.
  5. First use case: semantic search. Store embeddings from OpenAI/Cohere in documents.embedding, then query nearest neighbours:
    $vector = '[' . implode(',', $embedding) . ']';
    
    $results = DB::table('documents')
        ->select('id', 'title', 'body')
        ->orderByRaw('embedding <=> ?::vector', [$vector])
        ->limit(10)
        ->get();
    

Look first at the pgvector README’s SQL examples for operators, index types, and distance functions. Those translate directly to Laravel’s query builder and raw statements.

Implementation Patterns

Embedding storage and casting

Create a custom cast so models expose arrays while the database stores vector:

class VectorCast implements CastsAttributes
{
    public function get($model, $key, $value, $attributes)
    {
        return $value ? array_map('floatval', explode(',', trim($value, '[]'))) : null;
    }

    public function set($model, $key, $value, $attributes)
    {
        return $value ? '[' . implode(',', $value) . ']' : null;
    }
}

Use it on the model:

protected $casts = ['embedding' => VectorCast::class];

Generation workflow

  • Generate embeddings in queued jobs, not in HTTP requests.
  • Chunk long text before embedding; store source_id, chunk_index, and metadata alongside the vector.
  • Batch updates with DB::table('documents')->upsert(...) where possible.
  • Cache embeddings by content hash to avoid recomputing unchanged text.

Search patterns

Use the operator that matches your similarity metric:

Metric Operator Index opclass
Cosine distance <=> vector_cosine_ops
L2 distance <-> vector_l2_ops
Inner product <#> vector_ip_ops

Typical repository method:

public function nearest(array $embedding, int $limit = 10)
{
    $vector = '[' . implode(',', $embedding) . ']';

    return DB::table('documents')
        ->whereNotNull('embedding')
        ->orderByRaw('embedding <=> ?::vector', [$vector])
        ->limit($limit)
        ->get();
}

Indexing

Build indexes after bulk-loading data:

DB::statement('CREATE INDEX documents_embedding_hnsw_idx
    ON documents USING hnsw (embedding vector_cosine_ops)');

HNSW is usually the better default for read-heavy Laravel apps. IVFFlat is cheaper to build but needs representative data before index creation and requires tuning lists/probes.

Hybrid search

For RAG or search features, combine lexical and vector results:

  • Postgres full-text search with to_tsvector / plainto_tsquery.
  • Vector search with <=>.
  • Merge with reciprocal rank fusion in PHP or SQL.

Filtering

Apply tenant, status, or date filters in WHERE before ordering by distance. For large tenant-specific datasets, consider partial indexes or partitioning by tenant_id and querying within a partition.

RAG integration

Retrieve top-k chunks, pass them into your LLM prompt, and keep the retrieval layer behind a service class. This makes it easy to swap embedding models, index settings, or search strategies without touching controllers.

Gotchas and Tips

  • The gem is Ruby. Do not expect a Composer package named ankane/pgvector. Use the Postgres extension directly, or a PHP/Laravel wrapper such as pgvector/pgvector.
  • Extension permissions. CREATE EXTENSION vector may require superuser or platform-specific enablement. On managed Postgres, verify support before designing around it.
  • SQLite tests will not work. Any test touching vector columns or operators must run against Postgres. Use a dedicated Postgres test database or Docker service.
  • Dimensions are fixed. A vector(1536) column rejects other sizes. Changing embedding providers usually means a new column/table and a full re-embedding job.
  • Operator and index opclass must match. Using <=> with a vector_l2_ops index will not use the index efficiently. Keep metric choice consistent across schema, queries, and indexes.
  • Always use LIMIT. ORDER BY embedding <=> ... without a limit can scan and sort the entire table.
  • Filters can starve index scans. Postgres may scan the index and discard filtered rows. pgvector 0.8+ supports iterative scans; otherwise consider partial indexes or SET LOCAL hnsw.ef_search.
  • Tune session settings per query. hnsw.ef_search, ivfflat.probes, and maintenance_work_mem matter. Set them with SET LOCAL inside transactions where appropriate.
  • Build indexes after bulk loads. HNSW builds can be slow and memory-hungry. For large imports, load data first, then create the index.
  • Format vectors safely. Prefer parameter binding with a string literal like [0.1,0.2,...]. Never interpolate raw user input into SQL.
  • Handle nulls. Existing rows will have NULL embeddings. Exclude them from searches and backfill asynchronously.
  • Use the gem’s docs as SQL reference. The Ruby examples for distance operators, index creation, and tuning are directly portable to Laravel migrations and query builder calls.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource