qdrant_edge 0.8.0-dev.2 copy "qdrant_edge: ^0.8.0-dev.2" to clipboard
qdrant_edge: ^0.8.0-dev.2 copied to clipboard

On-device vector search for Dart and Flutter, powered by the qdrant-edge Rust engine through UniFFI — the same shared FFI crate as the Swift and Kotlin SDKs.

Qdrant Edge — Dart & Flutter #

On-device vector search for Dart and Flutter, powered by Qdrant Edge — the Qdrant search engine running in-process, no server and no network.

The SDK is a thin layer over the UniFFI binding generated from the shared qdrant-edge-ffi Rust crate — the same crate the Swift and Kotlin SDKs bind, so the three stay in lock-step by construction. Like the mobile SDKs, it builds --no-default-features, so the O(n²) search_matrix op is off the surface.

Quick start #

import 'dart:io';

import 'package:qdrant_edge/qdrant_edge.dart';

final dir = Directory.systemTemp.createTempSync('qdrant_edge');

final shard = EdgeShard.load(
  path: dir.path,
  config: EdgeConfig(
    vectorData: {'': VectorDataConfig(size: 4, distance: Distance.dot)},
  ),
);

shard.update(operation: UpdateOperation.upsertPoints(points: [
  Point(id: NumIdPointId(1), vector: SingleVector([1, 0, 0, 0])),
]));

final hits = shard.search(request: SearchRequest(
  query: NearestQuery(vector: DenseNamedVector([1, 0, 0, 0]), using: null),
  limit: 10,
));

See example/ for a runnable demo and test/ for load → upsert → search, persistence, and error-path coverage.

Public API #

lib/qdrant_edge.dart re-exports the generated binding through an explicit show list, so the public surface is only the domain API (EdgeShard, EdgeConfig, Point, the query/filter/vector/error types, …). The UniFFI plumbing (FfiConverter*, RustBuffer, the call-status *ErrorHandlers, the raw @Native C functions) lives in lib/src/ and is not exported — it stays out of the package's semver contract, so a future UniFFI bump can reshape it without breaking consumers. (Swift achieves the same by demoting plumbing to internal; Dart does it for free with a show list, which Kotlin/JVM cannot.)

How it works #

  • Bindings. lib/src/qdrant_edge_ffi.dart is generated by uniffi-bindgen-dart in library mode (it reads the UniFFI metadata embedded in the compiled cdylib; the crate uses setup_scaffolding!(), so there is no UDL). It is not committed — it is ~17k lines of machine output, .gitignored and regenerated by ./build.sh. Run ./build.sh once after a fresh checkout before dart test / dart analyze (the same way the Swift/Kotlin SDKs need their build script first). uniffi.toml pins the Dart package name so the generated @Native asset ids resolve. Only the small curated facade (lib/qdrant_edge.dart) is committed — it is the reviewed public surface.
  • Toolchain provenance. The bindgen must be built from the fork that carries the uniffi-0.32 + library-mode-CLI + enum-collision-fix work (upstream acterglobal/uniffi-dart lacks it, pending PRs #149 / #151 / #152): github.com/DenisovAV/uniffi-dart @ library-mode-cli. Point UNIFFI_BINDGEN_DART at that build. CI regenerates the binding and diffs the committed facade to guarantee the public surface stays in sync with the crate (the binding itself can't drift — it is always regenerated, never stored).
  • Native library. The engine is delivered as a Native Asset: dart test, dart run, and flutter test/flutter run invoke hook/build.dart automatically — no --enable-experiment flag on Dart 3.12+.

Distribution #

hook/build.dart provisions the engine three ways, in priority order, so the same hook serves both an in-tree developer and a pub.dev consumer:

  1. Local prebuiltnative/prebuilt/<os_arch>/ (or $QDRANT_EDGE_PREBUILT_DIR). A dev/CI override, e.g. dropping in a locally cross-built device library.
  2. From source (host, in-tree) — when the target is the host OS and the Cargo workspace is present, build with cargo +nightly (needs the nightly toolchain + protobuf). This is the fast path while developing inside the monorepo; incremental rebuilds re-run only when a source dir changes.
  3. Download — otherwise fetch the per-platform, SHA256-pinned archive from the GitHub Release (edge-dart-native-v$VERSION) and cache it under the platform cache dir. This is how a consumer with no Rust toolchain, and every cross-compile (device/emulator) target, is served — the same shape the Kotlin AAR and Swift XCFramework releases use.

.github/workflows/edge-dart-native.yml builds the eight cdylibs (Linux x86_64/arm64, Windows x86_64, macOS arm64, iOS arm64 device/simulator, Android arm64/x86_64), packages each as qdrant-edge-ffi-<os_arch>.tar.gz, and publishes them with a checksums.txt. Those SHA256 lines are pinned into the _sha256 table in hook/build.dart — the download path stays inert until they are, so a tampered or truncated archive can never be linked in.

The native-prebuilt release (edge-dart-native-v0.8.0) is cut and its checksums are pinned, so the package is publishable to pub.dev as qdrant_edge. Publishing regenerates the binding first (make publish runs ./build.sh then dart pub publish) so the generated glue lands in the archive even though it is .gitignored — .pubignore replaces .gitignore for pub and does not exclude it. native/ and the on-device harness stay out (a ~55 KB archive: the Dart glue ships as source, the native engine is downloaded at build time, never bundled).

Versioning #

The plugin tracks the native qdrant-edge library — lib/edge/VERSION, the same single source the Swift edge-v$VERSION tag and the Kotlin VERSION_NAME use — on major.minor, the API/ABI contract shared across every Edge SDK (0.8.x speaks the same surface on all platforms). lib/edge/VERSION and the qdrant-edge-ffi crate version are kept identical — they are the native version. The pub.dev version matches them on major.minor, but its patch floats independently: a Dart-only fix (a regenerated binding, a hook/build.dart change, docs) can ship as a new patch without cutting a fresh native release — it keeps downloading the prebuilt pinned by _releaseTag. So qdrant_edge 0.8.1 may wrap native 0.8.0, exactly as Rust -sys crates decouple their own version from the C library they bundle. edge-dart.yml enforces this: VERSION == crate exactly, and both the pubspec version and the hook's native pin must match VERSION on major.minor.

0
likes
0
points
283
downloads

Publisher

unverified uploader

Weekly Downloads

On-device vector search for Dart and Flutter, powered by the qdrant-edge Rust engine through UniFFI — the same shared FFI crate as the Swift and Kotlin SDKs.

Homepage
Repository (GitHub)
View/report issues

Topics

#vector-search #embeddings #database #ffi #on-device

License

unknown (license)

Dependencies

code_assets, crypto, ffi, hooks

More

Packages that depend on qdrant_edge