PHPackages                             mcpuishor/qdrant-laravel - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. mcpuishor/qdrant-laravel

ActiveLibrary[Database &amp; ORM](/categories/database)

mcpuishor/qdrant-laravel
========================

A fluent package to interact with Qdrant Vector Database

v0.2.0(1mo ago)917.0k↓58%5[1 issues](https://github.com/mcpuishor/qdrant-laravel/issues)MITPHPPHP ^8.2|^8.3|^8.4CI passing

Since Jun 21Pushed 1y ago1 watchersCompare

[ Source](https://github.com/mcpuishor/qdrant-laravel)[ Packagist](https://packagist.org/packages/mcpuishor/qdrant-laravel)[ RSS](/packages/mcpuishor-qdrant-laravel/feed)WikiDiscussions master Synced 2w ago

READMEChangelog (2)Dependencies (10)Versions (4)Used By (0)

Qdrant for Laravel
==================

[](#qdrant-for-laravel)

Introduction
------------

[](#introduction)

This package provides an elegant, fluent interface for interacting with the [Qdrant Vector Database](https://qdrant.tech/) in Laravel. Qdrant is a vector similarity search engine that makes it easy to store and search for embeddings, making it ideal for AI-powered applications.

Key features:

- Simple collection management
- Fluent search API with filtering and grouping
- Efficient point operations (insert, upsert, delete)
- Vector operations (update, delete)
- Laravel Facade support
- Convenient payload handling

Installation
------------

[](#installation)

### 1. Install via Composer

[](#1-install-via-composer)

```
composer require mcpuishor/qdrant-laravel
```

### 2. Publish the Configuration File

[](#2-publish-the-configuration-file)

```
php artisan vendor:publish --tag=qdrant-laravel-config
```

This will create a `config/qdrant-laravel.php` file where you can set your Qdrant connections and defaults.

### 3. Set Up Your `.env` File

[](#3-set-up-your-env-file)

Update your `.env` file with your Qdrant host details:

```
QDRANT_DEFAULT=main
QDRANT_HOST=http://localhost:6333
QDRANT_COLLECTION=collection_name
QDRANT_VECTOR_SIZE=1536
QDRANT_DEFAULT_DISTANCE_METRIC=Cosine
```

Configuration
-------------

[](#configuration)

The `config/qdrant-laravel.php` file allows multiple connections:

```
return [
    'default' => env('QDRANT_DEFAULT', 'main'),

    'connections' => [
        'main' => [
            'host' => env('QDRANT_HOST', 'http://localhost:6333'),
            'api_key' => env('QDRANT_API_KEY', null),
            'collection' => env('QDRANT_COLLECTION', 'default_collection'),
            'vector_size' => env('QDRANT_VECTOR_SIZE', 128),
        ],
    ],

    'default_distance_metric' => env('QDRANT_DEFAULT_DISTANCE_METRIC', 'Cosine'),
];
```

Schema Management (Migrations)
------------------------------

[](#schema-management-migrations)

### Creating a new collection

[](#creating-a-new-collection)

A collection must contain at least one vector. An optional parameter `options` can contain additional parameters described as an associative array. See the [Qdrant documentation](https://api.qdrant.tech/api-reference/collections/create-collection) for details. The options can be specified using arrays or DataObjects defined in the package.

The response is a boolean value, unless an exception is thrown.

```
use \Mcpuishor\QdrantLaravel\Facades\Schema;
use \Mcpuishor\QdrantLaravel\Enums\DistanceMetric;
use \Mcpuishor\QdrantLaravel\DTOs\Vector;

$vector = Vector::fromArray([
            'size' => 128,
            'distance' => DistanceMetric::COSINE
       ]);

$response = Schema::create(
                   name: "new_collection",
                   vector: $vector,
                   options: []
                );

if ($response) {
    echo "Schema created successfully";
}
```

### Creating a new collection on a different connection

[](#creating-a-new-collection-on-a-different-connection)

You can switch the connection at runtime. The connection must be defined in the `config\qdrant-laravel.php` file.

```
use \Mcpuishor\QdrantLaravel\Schema;
use \Mcpuishor\QdrantLaravel\Enums\DistanceMetric;
use \Mcpuishor\QdrantLaravel\DTOs\Vector;

$vector = Vector::fromArray([
            'size' => 128,
            'distance' => DistanceMetric::COSINE
       ]);

$response = Schema::connection('backup')
                ->create(
                   name: "new_collection",
                   vector: $vector,
                );

if ($response) {
    echo "Schema created successfully";
}
```

### Creating a collection with multiple vectors

[](#creating-a-collection-with-multiple-vectors)

A collection can contain multiple vectors per point. They need to be passed on to the `Schema::create`as an array containing the definitions of each vector. The vectors can have different definitions. The optional parameters can be specified using Data Objects defined in the package.

```
use \Mcpuishor\QdrantLaravel\Schema;
use \Mcpuishor\QdrantLaravel\QdrantTransport;
use \Mcpuishor\QdrantLaravel\Enums\DistanceMetric;
use \Mcpuishor\QdrantLaravel\DTOs\Vector;
use \Mcpuishor\QdrantLaravel\DTOs\HnswConfig;

$vector1 = Vector::fromArray([
            'size' => 128,
            'distance' => DistanceMetric::COSINE
            //optional parameters
            'on_disk' => true,
            ]);

$vector2 = Vector::fromArray([
            'size' => 1024,
            'distance' => DistanceMetric::COSINE,
            //optional parameters
            'hsnw_config' => Hnswconfig::fromArray([
                    'm' => 10,
                    'ef_construct' => 4,
                    'on_disk' => true,
                ]),
            ]);

$response = Schema::create(
               name: "new_collection",
               vector: array($vector1, $vector2),
            );

if ($response) {
    echo "Schema created successfully";
}
```

Deleting a collection
---------------------

[](#deleting-a-collection)

To delete a collection, you can call the `delete` method on the `Schema` facade. It returns a `Mcpuishor\QdrantLaravel\DTOs\Response` object.

```
use \Mcpuishor\QdrantLaravel\Facades\Schema;

$result = Schema::delete('collection_name');

if ($result) {
    echo "Collection has been successfully deleted.";
}
```

Collection existence
--------------------

[](#collection-existence)

To check if the collection defined in the config on the current connection exists:

```
use \Mcpuishor\QdrantLaravel\Facades\Schema;

if ( Schema::exists() ) {
    echo "Collection exists.";
}
```

At the same time, you can check the existence of a different collection on the same connection:

```
use \Mcpuishor\QdrantLaravel\Facades\Schema;

if ( Schema::exists( 'another_collection' ) ) {
    echo "Collection 'another_collection' exists.";
}
```

Updating a collection
---------------------

[](#updating-a-collection)

Updating parameters on an existing collection can be done in a similar fashion to creating one. The parameters updated can be specified using arrays or Data Objects defined in the package.

Updating the collection defined in the `config\qdrant-laravel.php`:

```
use \Mcpuishor\QdrantLaravel\Facades\Schema;
use \Mcpuishor\QdrantLaravel\DTOs\HnswConfig;
use \Mcpuishor\QdrantLaravel\DTOs\Collection\Params;

Schema::update(
    vectors: [

    ],
    options: [
       'hnsw_config' => HnswConfig::fromArray([
                'm' => 100,
                'ef_construct' => 5,
            ]),
       'params' => Params::fromArray([
                'replication_factor' => 4,
                'on_disk_payload' => true,
            ]),
    ]
);
```

Indexing a collection
---------------------

[](#indexing-a-collection)

Indexes in a Qdrant vector collection are created on the payload for each vector. For more details see the [Qdrant documentation](https://qdrant.tech/documentation/concepts/indexing/).

### Creating an index

[](#creating-an-index)

To create a payload index over a field:

```
use \Mcpuishor\QdrantLaravel\Facades\Qdrant;
use \Mcpuishor\QdrantLaravel\Enums\FieldType;

$result = Qdrant::indexes()->add('field_name', FieldType::KEYWORD);
```

It returns `true` if the operation was successful, or `false` otherwise.

You can use dot notation to create indexes over nested fields.

By default, indexes are stored in memory. If you have large indexes, and they need to be stored on the disk, you can use the `->onDisk()` method before creating the index. Choose carefully when to store an index on the disk, as this will introduce some latency in your future queries.

### Parameterized integer indexes

[](#parameterized-integer-indexes)

Qdrant v1.8.0 has introduced a parameterized variant of the integer index. To turn the parameterized index on you can call the `->parameterized()`method before creating an `integer` index. This setting is used only for `integer` fields in the payload.

Values of the `lookup` and `range` can be toggled in the `config\qdrant-laravel.php` file. For more information on parameterized integer indexes and how they affect performance check the [Qdrant documentation](https://qdrant.tech/documentation/concepts/indexing/#parameterized-index)

```
    $result = Qdrant::indexes()->parameterized()->add('field_name', FieldType::INTEGER);
```

It returns `true` if the operation was successful, or `false` otherwise.

### Full-text indexes

[](#full-text-indexes)

Qdrant supports full-text search for string payload. Full-text index allows you to filter points by the presence of a word or a phrase in the payload field.

```
    use \Mcpuishor\QdrantLaravel\Enums\TokenizerType;
    use \Mcpuishor\QdrantLaravel\Facades\Qdrant;

    $result = Qdrant::indexes()->fulltext('text_field_name', TokenizerType::WORD);
```

It returns `true` if the operation was successful, or `false` otherwise.

### Deleting an index

[](#deleting-an-index)

```
    use \Mcpuishor\QdrantLaravel\Facades\Qdrant;

    $result = Qdrant::indexes()->delete('payload_field');
```

It returns `true` if the operation was successful, or `false` otherwise.

Searching
---------

[](#searching)

The package provides a fluent interface for searching vectors in your Qdrant collection.

### Basic Vector Search

[](#basic-vector-search)

To perform a simple search with a vector:

```
use Mcpuishor\QdrantLaravel\Facades\Qdrant;

// Search using a vector
$results = Qdrant::search()
    ->vector([0.2, 0.3, 0.4, ...]) // Your vector data
    ->limit(10)
    ->get();
```

### Search by Point ID

[](#search-by-point-id)

You can also search for similar points to an existing point by its ID:

```
use Mcpuishor\QdrantLaravel\Facades\Qdrant;
use Mcpuishor\QdrantLaravel\DTOs\Point;

$point = new Point(id: 123);
$results = Qdrant::search()
    ->point($point)
    ->limit(5)
    ->get();
```

### Including Payload and Vectors

[](#including-payload-and-vectors)

Control what data is returned with your search results:

```
// Include all payload data
$results = Qdrant::search()
    ->vector($vector)
    ->withPayload()
    ->get();

// Include only specific payload fields
$results = Qdrant::search()
    ->vector($vector)
    ->include(['name', 'description'])
    ->get();

// Exclude specific payload fields
$results = Qdrant::search()
    ->vector($vector)
    ->exclude(['internal_id'])
    ->get();

// Include vector data in results
$results = Qdrant::search()
    ->vector($vector)
    ->withVectors()
    ->get();
```

### Pagination

[](#pagination)

Control the number of results and implement pagination:

```
// Limit results
$results = Qdrant::search()
    ->vector($vector)
    ->limit(20)
    ->get();

// Pagination with offset
$results = Qdrant::search()
    ->vector($vector)
    ->limit(10)
    ->offset(20) // Skip first 20 results
    ->get();
```

### Filtering Results

[](#filtering-results)

Apply filters to search results (and to `count`, `scroll`, `facet`, `discover` and `matrix`, since they all share the same `HasFilters` trait) using `must` / `mustNot` / `should` / `minShould`, each taking a payload key, a `FilterConditions` case, and the operand for that condition:

```
use Mcpuishor\QdrantLaravel\Enums\FilterConditions;

// Match filter (equality) — the value is wrapped under `match.value`
$results = Qdrant::search()
    ->vector($vector)
    ->must('category', FilterConditions::MATCH, 'electronics')
    ->get();

// Range filter — the operand is passed through as-is (gte/lte/gt/lt)
$results = Qdrant::search()
    ->vector($vector)
    ->must('price', FilterConditions::RANGE, ['gte' => 100, 'lte' => 500])
    ->get();

// Combine MUST and MUST NOT
$results = Qdrant::search()
    ->vector($vector)
    ->must('category', FilterConditions::MATCH, 'electronics')
    ->mustNot('discontinued', FilterConditions::MATCH, true)
    ->get();

// SHOULD (at least one of these should match) and MIN SHOULD (at least N of these)
$results = Qdrant::search()
    ->vector($vector)
    ->should('category', FilterConditions::MATCH, 'electronics')
    ->should('category', FilterConditions::MATCH, 'gadgets')
    ->minShould('tag', FilterConditions::MATCH, 'featured', min_count: 1)
    ->get();

// is_empty / is_null only need the key, no value
$results = Qdrant::search()
    ->vector($vector)
    ->must('description', FilterConditions::IS_EMPTY)
    ->get();
```

> **Note (issue #3, fixed in 0.2.0):** filter conditions used to serialize incorrectly for several `FilterConditions` cases. As of 0.2.0, `match` correctly wraps its operand under `{"match": {"value": ...}}`, `range`/`geo_bounding_box`/`geo_polygon`/`geo_radius`/`values_count` pass their operand through unwrapped (e.g. `{"range": {"gte": 100}}`), and `is_empty`/`is_null` emit `{"is_empty": {"key": "..."}}` with no value at all. If you built filters against a version prior to 0.2.0, re-check any `range`, `is_empty`, or `is_null` filters — their JSON shape has changed.

### Grouping Results

[](#grouping-results)

Group search results by a payload field:

```
// Group results by category
$results = Qdrant::search()
    ->vector($vector)
    ->groupBy('category', 5) // 5 results per group
    ->get();
```

### Batch Searching

[](#batch-searching)

Perform multiple searches in a single request:

```
$search1 = Qdrant::search()->vector($vector1)->limit(5);
$search2 = Qdrant::search()->vector($vector2)->limit(5);

$batchResults = Qdrant::search()->batch([$search1, $search2]);
```

### Random Sampling

[](#random-sampling)

Get random points from the collection:

```
$randomPoints = Qdrant::search()->random();
```

### Using Named Vectors

[](#using-named-vectors)

If your collection has multiple named vectors, specify which one to use:

```
$results = Qdrant::search()
    ->vector($vector)
    ->using('image_embedding') // Use the named vector
    ->get();
```

Recommendations
---------------

[](#recommendations)

The package provides a recommendation system based on positive and negative examples.

### Basic Recommendations

[](#basic-recommendations)

Get recommendations based on positive examples:

```
use Mcpuishor\QdrantLaravel\Facades\Qdrant;

// Recommend based on point IDs
$recommendations = Qdrant::recommend()
    ->positive([123, 456]) // Points you like
    ->limit(10)
    ->get();
```

### Positive and Negative Examples

[](#positive-and-negative-examples)

Refine recommendations with both positive and negative examples:

```
$recommendations = Qdrant::recommend()
    ->positive([123, 456]) // Points you like
    ->negative([789, 101]) // Points you don't like
    ->limit(10)
    ->get();
```

### Recommendation Strategy

[](#recommendation-strategy)

Control how vectors are combined for recommendations:

```
use Mcpuishor\QdrantLaravel\Enums\AverageVectorStrategy;

$recommendations = Qdrant::recommend()
    ->positive([123, 456])
    ->strategy(AverageVectorStrategy::WEIGHTED) // Use weighted average
    ->limit(10)
    ->get();
```

Available strategies include:

- `AverageVectorStrategy::MEAN` - Simple average of vectors
- `AverageVectorStrategy::WEIGHTED` - Weighted average based on similarity

Point Operations
----------------

[](#point-operations)

The package provides methods for managing points in your Qdrant collection.

### Retrieving Points

[](#retrieving-points)

Get points by their IDs:

```
use Mcpuishor\QdrantLaravel\Facades\Qdrant;

// Get multiple points
$points = Qdrant::points()->get([123, 456, 789]);

// Find a single point
$point = Qdrant::points()->find(123);
```

### Controlling Returned Data

[](#controlling-returned-data)

Control what data is returned with the points:

```
// With payload (default)
$points = Qdrant::points()->withPayload()->get([123, 456]);

// Without payload
$points = Qdrant::points()->withoutPayload()->get([123, 456]);

// With vector data
$points = Qdrant::points()->withVector()->get([123, 456]);

// Without vector data (default)
$points = Qdrant::points()->withoutVector()->get([123, 456]);
```

### Inserting Points

[](#inserting-points)

Insert a new point into the collection:

```
use Mcpuishor\QdrantLaravel\DTOs\Point;

// Create a point
$point = new Point(
    id: 123,
    vector: [0.2, 0.3, 0.4, ...],
    payload: ['name' => 'Example', 'category' => 'test']
);

// Insert the point
$success = Qdrant::points()->insert($point);
```

### Upserting Points

[](#upserting-points)

Insert or update multiple points:

```
use Mcpuishor\QdrantLaravel\PointsCollection;
use Mcpuishor\QdrantLaravel\DTOs\Point;

// Create points collection
$points = new PointsCollection([
    new Point(id: 123, vector: [0.2, 0.3, 0.4, ...], payload: ['name' => 'First']),
    new Point(id: 456, vector: [0.5, 0.6, 0.7, ...], payload: ['name' => 'Second'])
]);

// Upsert the points
$success = Qdrant::points()->upsert($points);
```

### Deleting Points

[](#deleting-points)

Delete points by their IDs:

```
// Delete specific points
$success = Qdrant::points()->delete([123, 456]);

// Delete points matching a filter
$success = Qdrant::points()
    ->where('category', '=', 'test')
    ->delete([]);
```

### Autochunking

[](#autochunking)

Efficiently handle large numbers of points with automatic chunking:

```
// Create an autochunker with chunk size of 100
$chunker = Qdrant::points()->autochunk(100);

// Add points - they'll be automatically upserted when the chunk size is reached
foreach ($largeDataset as $data) {
    $point = new Point(
        id: $data['id'],
        vector: $data['embedding'],
        payload: $data['metadata']
    );
    $chunker->add($point);
}

// Manually flush any remaining points
$chunker->flush();
```

Vector Operations
-----------------

[](#vector-operations)

The package provides methods for managing vectors in your Qdrant collection.

### Updating Vectors

[](#updating-vectors)

Update vectors for existing points:

```
use Mcpuishor\QdrantLaravel\Facades\Qdrant;
use Mcpuishor\QdrantLaravel\PointsCollection;
use Mcpuishor\QdrantLaravel\DTOs\Point;

// Create a collection of points with updated vectors
$points = new PointsCollection([
    new Point(id: 123, vector: [0.2, 0.3, 0.4, ...]),
    new Point(id: 456, vector: [0.5, 0.6, 0.7, ...])
]);

// Update the vectors
$success = Qdrant::vectors()->update($points);
```

### Deleting Vectors

[](#deleting-vectors)

Delete vectors for specific points:

```
use Mcpuishor\QdrantLaravel\Facades\Qdrant;

// Delete vectors for specific points
$success = Qdrant::vectors()->delete([123, 456]);
```

Collection Aliases
------------------

[](#collection-aliases)

Aliases let you point a stable name at a collection and swap the underlying collection atomically — useful for zero-downtime reindexing (build `plants_v2`, then repoint the `plants` alias to it).

Alias mutations are queued fluently and committed with a single `apply()` call:

```
use Mcpuishor\QdrantLaravel\Facades\Qdrant;

// Create an alias, or several, then commit them in one atomic request
Qdrant::collection('plants')->aliases()
    ->add('plants', 'plants_v2')   // alias name, target collection
    ->delete('plants_old')
    ->apply(); // bool

// Atomically move an alias from its current target to a new collection
Qdrant::collection('plants')->aliases()
    ->switch('plants', 'plants_v2') // delete + re-add in one request
    ->apply();
```

`apply()` throws a `CommandException` if no actions have been queued.

List aliases — scoped to the current collection, or all aliases across the server:

```
// Aliases pointing at the current collection
$aliases = Qdrant::collection('plants')->aliases()->get(); // Illuminate\Support\Collection

// All aliases on the server (no collection scope)
$all = Qdrant::aliases()->get();
```

New in 0.2.0
------------

[](#new-in-020)

Version 0.2.0 adds full coverage of the Qdrant 1.18.x REST API — counting, scrolling, batch updates, named-vector management, facets, discovery, a distance matrix, service/health/telemetry, snapshots (collection/storage/shard), cluster management, shard keys, and beta issues — plus the issue #3 filter fix described above.

### Counting Points

[](#counting-points)

Count points matching (optional) filters without fetching them:

```
use Mcpuishor\QdrantLaravel\Facades\Qdrant;
use Mcpuishor\QdrantLaravel\Enums\FilterConditions;

$total = Qdrant::collection('plants')
    ->count()
    ->exact()
    ->must('category', FilterConditions::MATCH, 'tropical')
    ->get(); // int
```

### Scrolling Through Points

[](#scrolling-through-points)

Page through a collection's points without vector search, optionally ordered by a payload key:

```
$scroll = Qdrant::collection('plants')
    ->scroll()
    ->limit(50)
    ->orderBy('created_at', 'desc')
    ->withPayload()
    ->withVector();

$page = $scroll->get();               // PointsCollection
$nextOffset = $scroll->nextPageOffset(); // pass this to ->offset() on the next call
```

### Batch Updates

[](#batch-updates)

Combine multiple point/payload/vector operations into a single request:

```
use Mcpuishor\QdrantLaravel\PointsCollection;

$success = Qdrant::collection('plants')
    ->batch()
    ->upsert($pointsCollection) // a PointsCollection
    ->deletePoints([1, 2, 3])
    ->setPayload(['watered' => true], points: [4, 5])
    ->clearPayload(points: [6])
    ->updateVectors($otherPointsCollection)
    ->deleteVectors(ids: [7, 8], vectorNames: ['image_embedding'])
    ->execute(); // bool
```

### Named Vectors

[](#named-vectors)

Add, remove, or inspect named vector configurations on an existing collection:

```
use Mcpuishor\QdrantLaravel\DTOs\Vector;
use Mcpuishor\QdrantLaravel\Enums\DistanceMetric;

Qdrant::collection('plants')->namedVectors()->create(
    'image_embedding',
    Vector::fromArray(['size' => 512, 'distance' => DistanceMetric::COSINE])
);

Qdrant::collection('plants')->namedVectors()->delete('image_embedding');

$status = Qdrant::collection('plants')->namedVectors()->optimizations(); // array
```

### Facets

[](#facets)

Get distinct payload values (and their counts) for a key, similar to a search facet/aggregation:

```
$facets = Qdrant::collection('plants')
    ->facet('category')
    ->limit(20)
    ->exact()
    ->get(); // FacetResponse

foreach ($facets->hits() as $hit) {
    // ['value' => ..., 'count' => ...]
}
```

### Discovery

[](#discovery)

Find points using positive/negative context pairs plus an optional target — Qdrant's discovery search:

```
$results = Qdrant::collection('plants')
    ->discover()
    ->target(123)
    ->context([['positive' => 456, 'negative' => 789]])
    ->using('image_embedding')
    ->limit(10)
    ->get(); // PointsCollection

// Batch discovery
$batchResults = Qdrant::collection('plants')->discover()->batch([$discover1, $discover2]);
```

### Recommendations on the Query API

[](#recommendations-on-the-query-api)

`Qdrant::recommend()` is rebuilt on top of the Query API (`POST /points/query`) internally, so the public interface is unchanged — see the [Recommendations](#recommendations) section above.

### Distance Matrix

[](#distance-matrix)

Compute pairwise distances between a sample of points:

```
$offsets = Qdrant::collection('plants')
    ->matrix()
    ->sample(50)
    ->limit(10)
    ->using('image_embedding')
    ->offsets(); // array

$pairs = Qdrant::collection('plants')->matrix()->sample(50)->pairs(); // array
```

### Service, Health, and Telemetry

[](#service-health-and-telemetry)

Inspect the Qdrant server itself, independent of any collection:

```
Qdrant::service()->root();          // array — server identity/version
Qdrant::service()->healthz();       // bool
Qdrant::service()->livez();         // bool
Qdrant::service()->readyz();        // bool
Qdrant::service()->telemetry();     // array
Qdrant::service()->metrics();       // string — Prometheus text format
```

### Collection Snapshots

[](#collection-snapshots)

Create, list, delete, and download snapshots of a collection:

```
$snapshot = Qdrant::collection('plants')->snapshots()->create(); // SnapshotDescription

Qdrant::collection('plants')->snapshots()->list();               // Collection
Qdrant::collection('plants')->snapshots()->delete($snapshot->name);
Qdrant::collection('plants')->snapshots()->download($snapshot->name); // Illuminate\Http\Client\Response

// Recover from (register) a snapshot that already exists at a server-visible location
Qdrant::collection('plants')->snapshots()->recover('file:///qdrant/snapshots/plants/plants.snapshot');
```

> **Limitation:** `snapshots()->upload($path)` currently throws a `SnapshotException` — multipart upload of local file bytes from your application to the server is not yet implemented. Use `recover($location)`with a path the **Qdrant server** can already see instead.

### Storage Snapshots

[](#storage-snapshots)

Snapshot the entire storage (not tied to a single collection):

```
$snapshot = Qdrant::storageSnapshots()->create(); // SnapshotDescription
Qdrant::storageSnapshots()->list();
Qdrant::storageSnapshots()->delete($snapshot->name);
Qdrant::storageSnapshots()->download($snapshot->name);
```

### Shard Snapshots

[](#shard-snapshots)

Snapshot an individual shard in a distributed deployment:

```
$snapshot = Qdrant::collection('plants')->shardSnapshots(shardId: 0)->create(); // SnapshotDescription
Qdrant::collection('plants')->shardSnapshots(0)->list();
Qdrant::collection('plants')->shardSnapshots(0)->delete($snapshot->name);
Qdrant::collection('plants')->shardSnapshots(0)->download($snapshot->name);
Qdrant::collection('plants')->shardSnapshots(0)->recover('file:///qdrant/snapshots/plants/0/shard.snapshot');
```

### Cluster Management

[](#cluster-management)

Inspect and manage a distributed Qdrant cluster:

```
$status = Qdrant::collection('plants')->cluster()->status(); // ClusterStatus
Qdrant::collection('plants')->cluster()->telemetry();         // array
Qdrant::collection('plants')->cluster()->recover();           // bool
Qdrant::collection('plants')->cluster()->removePeer(peerId: 4, force: false);
Qdrant::collection('plants')->cluster()->collection();        // array — this collection's cluster info
Qdrant::collection('plants')->cluster()->moveShard(shardId: 0, fromPeer: 1, toPeer: 2);
Qdrant::collection('plants')->cluster()->replicateShard(shardId: 0, fromPeer: 1, toPeer: 2);
```

### Shard Keys

[](#shard-keys)

Manage custom sharding for a collection:

```
Qdrant::collection('plants')->shards()->keys();          // array
Qdrant::collection('plants')->shards()->create('region-eu');
Qdrant::collection('plants')->shards()->delete('region-eu');
```

### Issues (Beta)

[](#issues-beta)

Read and clear the server's self-diagnosed issues (a beta Qdrant API):

```
Qdrant::issues()->get();   // array
Qdrant::issues()->clear(); // bool
```

Artisan Commands
----------------

[](#artisan-commands)

### Creating a Collection with indexes

[](#creating-a-collection-with-indexes)

```
php artisan qdrant:migrate --collection=plants --vector-size=256 --distance-metric=euclidean --indexes='{"species":"text","age":"integer"}'
```

### Rolling Back a Migration (Dropping Collection &amp; Indexes)

[](#rolling-back-a-migration-dropping-collection--indexes)

```
php artisan qdrant:migrate --rollback --collection=plants
```

Extending with Macros
---------------------

[](#extending-with-macros)

The query builder and client are **Macroable**, allowing custom methods:

```
use Mcpuishor\QdrantLaravel\QdrantClient;

QdrantClient::macro('byClimate', function ($climate) {
    return $this->where('climate', '=', $climate);
});

$results = Qdrant::collection('plants')->byClimate('tropical')->get();
```

Conclusion
----------

[](#conclusion)

This package simplifies working with Qdrant in Laravel, making it easy to integrate **vector search** and **AI-powered applications**. Contributions are welcome!

---

### **License**

[](#license)

This package is open-source and available under the [MIT License](LICENSE).

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance65

Regular maintenance activity

Popularity34

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 98.7% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~380 days

Total

2

Last Release

44d ago

PHP version history (2 changes)v0.1.0PHP ^8.2|^8.3

v0.2.0PHP ^8.2|^8.3|^8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/f68447628fda07406fb838fc490d8935d415088a93ec70584f59db2f719637c4?d=identicon)[mcpuishor](/maintainers/mcpuishor)

---

Top Contributors

[![mcpuishor](https://avatars.githubusercontent.com/u/40750444?v=4)](https://github.com/mcpuishor "mcpuishor (78 commits)")[![happyDemon](https://avatars.githubusercontent.com/u/38573?v=4)](https://github.com/happyDemon "happyDemon (1 commits)")

---

Tags

laravelqdrantvector-database

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/mcpuishor-qdrant-laravel/health.svg)

```
[![Health](https://phpackages.com/badges/mcpuishor-qdrant-laravel/health.svg)](https://phpackages.com/packages/mcpuishor-qdrant-laravel)
```

###  Alternatives

[illuminate/database

The Illuminate Database package.

2.8k55.8M13.1k](/packages/illuminate-database)[mongodb/laravel-mongodb

A MongoDB based Eloquent model and Query builder for Laravel

7.1k8.9M110](/packages/mongodb-laravel-mongodb)[yajra/laravel-oci8

Oracle DB driver for Laravel via OCI8

8723.3M27](/packages/yajra-laravel-oci8)[glushkovds/phpclickhouse-laravel

Adapter of the most popular library https://github.com/smi2/phpClickHouse to Laravel

2051.6M2](/packages/glushkovds-phpclickhouse-laravel)[lemaur/eloquent-publishing

218.5k1](/packages/lemaur-eloquent-publishing)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
