qdrant_dart 0.3.0 copy "qdrant_dart: ^0.3.0" to clipboard
qdrant_dart: ^0.3.0 copied to clipboard

An idiomatic, REST-first Dart SDK for Qdrant.

qdrant_dart #

An idiomatic, REST-first Dart SDK for Qdrant.

Status: v0.3.0 is release-ready for collection lifecycle, typed search, payload and vector maintenance, filtered deletion and counts, and bounded batch ingestion.

Why this exists #

Qdrant has an OpenAPI and gRPC interface, but Dart developers need more than generated protocol classes: a small, predictable client with typed errors, practical pagination, and real compatibility checks against Qdrant.

qdrant_dart targets trusted Dart services, CLIs, and controlled application backends. Do not put a Qdrant Cloud API key in a mobile or browser app.

Product boundary #

  • REST is the first transport. gRPC is a later performance feature, not a prerequisite for a usable SDK.
  • The public API is handwritten and Dart-idiomatic; protocol generation, if used, stays an internal implementation detail.
  • Qdrant remains the database and the source of API semantics. This package will not add local vector storage, embedding generation, ORM behaviour, or a RAG framework.
  • Each supported endpoint must be covered by a real Qdrant integration test, not only mocked HTTP tests.

v0.1 scope #

  1. Client configuration, API-key authentication, timeouts, and typed errors.
  2. Collections: create, inspect, list, and delete.
  3. Points: upsert, retrieve, delete, scroll, and query with payload filters.
  4. A Docker-backed compatibility suite pinned to a declared Qdrant version.

gRPC, cluster administration, snapshots, shard management, and local embedding inference are explicitly out of scope for v0.1.

See CHANGELOG.md for release notes.

Compatibility #

Development is verified against a minimum supported Qdrant v1.12.0 and the current target v1.18.2. tool/qdrant-min-version and tool/qdrant-version are the sources of truth used by the compatibility harness.

The SDK supports HTTP/HTTPS client configuration, API-key authentication, request timeouts, typed failure reporting, and collection lifecycle operations plus point upsert, retrieval, ID- or filter-based deletion, exact or approximate counts, ID-ordered scrolling, and dense-vector queries with match/range payload filters, nested Boolean groups, and point-ID conditions against qdrant/qdrant:v1.18.2. Payload data can be set, overwritten, partially deleted, or cleared by point IDs or filters. Collection creation and point operations support one default dense vector or named dense and sparse vectors, and payload indexes can be created, inspected, and deleted. Selected vectors can be updated or named vectors deleted without replacing the rest of a point. Sparse-vector configuration currently uses Qdrant's defaults; nested payload filters and collection tuning are not yet supported. Large point iterables can be upserted in bounded sequential batches without hiding any per-batch update result.

Client setup #

Use the client only in a trusted Dart service or CLI. Read API keys from the server-side environment rather than embedding them in a Flutter or browser application.

import 'dart:io';

import 'package:qdrant_dart/qdrant_dart.dart';

final client = QdrantClient(
  baseUrl: Uri.parse('https://your-qdrant.example'),
  apiKey: Platform.environment['QDRANT_API_KEY'],
);

try {
  await client.collections.create(
    'movies',
    vectors: CollectionVectors.dense(
      DenseVectorParams(size: 4, distance: Distance.cosine),
    ),
  );
  await client.payloadIndexes.create(
    'movies',
    'year',
    schema: PayloadSchemaType.integer,
  );
  final update = await client.points.upsert('movies', [
    Point(
      id: 1,
      vector: [0.9, 0.1, 0.1, 0.2],
      payload: {'title': 'The Matrix', 'year': 1999},
    ),
    Point(
      id: 2,
      vector: [0.1, 0.9, 0.2, 0.1],
      payload: {'title': 'The Matrix Reloaded', 'year': 2003},
    ),
  ]);
  print(update.status);
  final stored = await client.points.retrieve(
    'movies',
    [1],
    withVectors: const VectorSelector.all(),
  );
  print(stored.single.payload?['title']);
  await for (final point in client.points.scrollAll('movies')) {
    print(point.id);
  }
  final matches = await client.points.query(
    'movies',
    DenseVector([0.9, 0.1, 0.1, 0.2]),
    filter: Filter(
      must: [
        HasIdCondition([1]),
        FieldCondition.match('year', 1999),
      ],
    ),
    withPayload: true,
  );
  print(matches.single.score);
  await client.points.setPayload(
    'movies',
    {'featured': true},
    PointSelector.ids([1]),
  );
  await client.points.overwritePayload(
    'movies',
    {'title': 'The Matrix', 'year': 1999},
    PointSelector.ids([1]),
  );
  await client.points.deletePayload(
    'movies',
    ['year'],
    PointSelector.ids([1]),
  );
  await client.points.clearPayload(
    'movies',
    PointSelector.filter(
      Filter(must: [FieldCondition.match('title', 'The Matrix')]),
    ),
  );
  print(await client.points.count('movies'));
  await client.points.deleteByFilter(
    'movies',
    Filter(must: [FieldCondition.range('year', gte: 2000)]),
  );
  await client.points.delete('movies', [1]);
  await client.payloadIndexes.delete('movies', 'year');
  final movies = await client.collections.get('movies');
  print(movies.pointsCount);
  await client.collections.delete('movies');
} finally {
  client.close();
}

Named dense and sparse vectors share the same point and query APIs:

await client.collections.create(
  'documents',
  vectors: CollectionVectors.named(
    dense: {
      'text': DenseVectorParams(size: 4, distance: Distance.cosine),
    },
    sparse: const {'keywords': SparseVectorParams()},
  ),
);
await client.points.upsert('documents', [
  Point.named(
    id: 1,
    vectors: {
      'text': DenseVector([0.9, 0.1, 0.1, 0.2]),
      'keywords': SparseVector(indices: [1, 5], values: [0.8, 0.4]),
    },
  ),
]);
await client.points.updateVectors('documents', [
  PointVectorUpdate.named(
    id: 1,
    vectors: {'text': DenseVector([0.8, 0.2, 0.1, 0.3])},
  ),
]);
final sparseMatches = await client.points.query(
  'documents',
  SparseVector(indices: [1, 5], values: [0.8, 0.4]),
  using: 'keywords',
  withVectors: VectorSelector.named(['text']),
);
await client.points.deleteVectors(
  'documents',
  ['keywords'],
  PointSelector.ids([1]),
);

For larger inputs, bound each request without first copying the entire iterable:

final updates = await client.points.upsertInBatches(
  'documents',
  generatedPoints,
  batchSize: 100,
);
for (final update in updates) {
  print(update.status);
}

Batches are sent sequentially. If one request fails, Qdrant does not roll back earlier successful batches.

When an operation fails, catch [QdrantException]. It includes the HTTP status when Qdrant responded, its error message when available, and the request method and URL. It never includes the API key.

Development #

Install Dart and Docker, then run:

dart pub get
dart format --output=none --set-exit-if-changed .
dart analyze --fatal-infos
dart test --exclude-tags integration
./tool/test-compatibility.sh

The compatibility script runs the real-server integration suite against both declared Qdrant versions. Each image starts on a random localhost port and is removed after its tests finish.

Releasing #

Releases are tag-driven. Update pubspec.yaml and CHANGELOG.md in the same commit, then create and push an annotated v<version> tag whose version exactly matches the package version. The publish workflow reruns the full CI suite and, only after it passes, uses GitHub OIDC and Dart's official reusable workflow to publish to pub.dev. No long-lived publishing token is stored in GitHub.

Automated publishing must be enabled on the package's pub.dev Admin page for the songxychn/qdrant-dart repository with tag pattern v{{version}} and the required GitHub Actions environment pub.dev.

For contributors and agents #

Read PROJECT.md for the roadmap and AGENTS.md for the delivery rules before adding code.

1
likes
0
points
29
downloads

Publisher

unverified uploader

Weekly Downloads

An idiomatic, REST-first Dart SDK for Qdrant.

Repository (GitHub)
View/report issues

Topics

#qdrant #vector-database #search

License

unknown (license)

More

Packages that depend on qdrant_dart