Looking to hire Laravel developers? Try LaraJobs

laravel-mariadb-vector maintained by devilsberg

Description
MariaDB 11.7+ native vector storage and search for Laravel Eloquent models
Author
Last update
2026/03/26 14:53 (v1.2.0)
License
Links
Downloads
2

Comments
comments powered by Disqus

Laravel MariaDB Vector

Latest Version on Packagist Tests License Ko-fi

MariaDB 11.7+ native vector storage and search for Laravel.

This package brings vector column support, binary-safe casting, and similarity search macros to Eloquent — powered by MariaDB's native VECTOR type and VEC_DISTANCE_* functions. Think of it as the MariaDB equivalent of pgvector for Laravel.

Requirements

  • PHP 8.4+
  • Laravel 12+
  • MariaDB 11.7+

Installation

composer require devilsberg/laravel-mariadb-vector

Publish the config file:

php artisan vendor:publish --tag=mariadb-vector-config

Quick Start

1. Create a migration

Schema::create('articles', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->text('body');
    $table->vector('embedding', 768);
    $table->timestamps();
});

2. Set up your model

use Devilsberg\LaravelMariadbVector\Casts\VectorCast;

class Article extends Model
{
    protected function casts(): array
    {
        return [
            'embedding' => VectorCast::class,
        ];
    }
}

3. Store a vector

$embedding = $yourEmbeddingProvider->embed($article->body); // your code

$article->embedding = $embedding; // float array, e.g. [0.1, 0.2, ...]
$article->save();

4. Search by similarity

$queryVector = $yourEmbeddingProvider->embed('climate change effects');

$results = Article::query()
    ->whereVectorSimilarTo('embedding', $queryVector, 0.5)
    ->orderByVectorDistance('embedding', $queryVector)
    ->selectVectorDistance('embedding', $queryVector, as: 'score')
    ->get();

Bring Your Own Embeddings

This package handles storage and search only. You generate embeddings however you want — Ollama, Mistral, Cohere, a local Python model, or anything that produces a float array.

// Ollama (local)
$response = Http::post('http://localhost:11434/api/embed', [
    'model' => 'nomic-embed-text',
    'input' => $text,
]);
$embedding = $response->json('embeddings.0');

// Mistral
$response = Http::withToken(config('services.mistral.key'))
    ->post('https://api.mistral.ai/v1/embeddings', [
        'model' => 'mistral-embed',
        'input' => [$text],
    ]);
$embedding = $response->json('data.0.embedding');

// Any source — just pass a float array
$article->embedding = $embedding;
$article->save();

VectorCast

VectorCast handles conversion between MariaDB's binary VECTOR format and PHP float arrays.

protected function casts(): array
{
    return [
        'embedding' => \Devilsberg\LaravelMariadbVector\Casts\VectorCast::class,
    ];
}
  • Reading: Decodes MariaDB's binary packed floats (32-bit IEEE 754) or JSON string format to array<float>
  • Writing: Converts array<float> to a VEC_FromText('[0.1, 0.2, ...]') expression
  • Null-safe: Returns null for null values in both directions
  • Empty-safe: Returns null for empty arrays

The column supports ->nullable() in migrations:

$table->vector('embedding', 768)->nullable();

Query Builder Macros

All macros are registered on Illuminate\Database\Eloquent\Builder.

whereVectorSimilarTo

Filter results by vector distance threshold.

whereVectorSimilarTo(
    string $column,
    array $input,
    float $threshold,       // required — what counts as "similar" is application-specific
    ?string $metric = null  // defaults to config('vector.distance_metric')
)
Article::query()->whereVectorSimilarTo('embedding', $queryVector, 0.5)->get();

// Euclidean distance
Article::query()->whereVectorSimilarTo('embedding', $queryVector, 0.5, metric: 'EUCLIDEAN')->get();

Generates: WHERE VEC_DISTANCE_COSINE(\embedding`, VEC_FromText(?)) < ?`

orderByVectorDistance

Sort results by vector distance (nearest first).

orderByVectorDistance(
    string $column,
    array $input,
    ?string $metric = null
)
Article::query()->orderByVectorDistance('embedding', $queryVector)->get();

Generates: ORDER BY VEC_DISTANCE_COSINE(\embedding`, VEC_FromText(?)) asc`

selectVectorDistance

Include the distance score in query results.

selectVectorDistance(
    string $column,
    array $input,
    string $as = 'distance',
    ?string $metric = null
)
Article::query()
    ->select('*')
    ->selectVectorDistance('embedding', $queryVector, as: 'score')
    ->orderByVectorDistance('embedding', $queryVector)
    ->get()
    ->each(fn ($article) => dump($article->title, $article->score));

Generates: VEC_DISTANCE_COSINE(\embedding`, VEC_FromText(?)) as `score``

Combining macros

$results = Article::query()
    ->select('id', 'title')
    ->whereVectorSimilarTo('embedding', $queryVector, 0.4)
    ->selectVectorDistance('embedding', $queryVector, as: 'score')
    ->orderByVectorDistance('embedding', $queryVector)
    ->limit(10)
    ->get();

Configuration

Published to config/vector.php:

return [
    // Default vector dimensions (should match your embedding model output)
    'default_dimensions' => 768,

    // Distance metric: "COSINE" or "EUCLIDEAN"
    'distance_metric' => 'COSINE',
];
Key Default Description
default_dimensions 768 Default dimensions for vector columns
distance_metric COSINE Distance function: COSINE or EUCLIDEAN

Note: DOT product distance is not supported by MariaDB. Configuring it will throw an InvalidArgumentException.

Testing

Run the unit tests:

vendor/bin/phpunit --testsuite=Unit

Run the integration tests (requires a live MariaDB instance):

vendor/bin/phpunit --testsuite=Integration

Configure MariaDB credentials in phpunit.xml:

<php>
    <env name="DB_HOST" value="127.0.0.1"/>
    <env name="DB_PORT" value="3306"/>
    <env name="DB_DATABASE" value="your_test_db"/>
    <env name="DB_USERNAME" value="your_user"/>
    <env name="DB_PASSWORD" value="your_password"/>
</php>

Run the full suite:

vendor/bin/phpunit

Support

If this package saves you time, consider buying me a coffee.

ko-fi

License

The MIT License (MIT). Please see License File for more information.