Skip to content

Edge CLI reference

The CLI exposes the edge backend through a global --edge flag plus a dedicated qql edge subcommand group and qql config edge configuration subcommand. Edge must be compiled in first — see getting started.

--edge is a global flag, not a subcommand. Add it to any execution-facing command to route it to the in-process backend instead of QDRANT_URL:

CommandRemote formEdge form
Run one statement or scriptqql run "…"qql --edge run "…"
Run a .qql fileqql run file.qqlqql --edge run file.qql
Interactive REPLqql replqql --edge repl
Export a collectionqql dump docs out.qqlqql --edge dump docs out.qql
Health checkqql doctorqql --edge doctor
Merge segments / build indexesqql edge optimize docs
Seed from a remote shard snapshotqql edge bootstrap docs --from http://host:6333
Edge examples
qql --edge run "SHOW COLLECTIONS" qql --edge run "QUERY 'hello' FROM docs USING dense LIMIT 5" qql --edge run first-local.qql qql --edge dump docs backup.qql qql --edge repl qql edge optimize docs qql edge bootstrap docs --from http://localhost:6333

qql explain needs no backend and therefore no --edge flag — planning is identical for remote and edge backends.

qdrant-edge has no background optimizer. Segments are merged and HNSW / sparse indexes are built only when optimization is explicitly requested, so a bulk-loaded collection can serve search from unindexed (brute-force) segments indefinitely. qql edge optimize <collection> runs the engine's blocking optimizer loop until no plan remains and prints the counts before and after:

Optimized 'docs': 5 → 2 segments, 300 points, indexed 0 → 300

or, when nothing needed rebuilding:

'collection' is already optimal: 2 segments, 300 points, indexed 300

The command builds the edge backend directly (no embedding model is loaded or downloaded). --json emits operation: "edge-optimize", optimized, and before/after {points, indexed, segments} objects. When indexed_vectors_count < points_count after optimizing, the result carries status: "warn" / indexing_lag: true and the message reports the exact lag instead of claiming success — the command still exits zero.

Run it after bulk writes, or when qql --edge doctor / qql check --edge reports indexing lag (see below). Small collections can legitimately stay unindexed: the indexing optimizer only builds HNSW for segments above the collection's indexing_threshold (10 MB by default offline, configurable with WITH OPTIMIZERS (indexing_threshold = …)).

qql edge bootstrap <collection> --from <remote-url> seeds a local edge collection from a remote Qdrant shard snapshot — the documented "offload indexing" flow. The snapshot is streamed from GET /collections/{c}/shards/{id}/snapshot, unpacked with the engine's snapshot API into a staging directory, verified by loading it, and only then moved into the data directory. It carries the source collection's configuration, built HNSW indexes and quantized data, so the device does not re-index anything.

Flags:

FlagPurpose
--from <url>Remote Qdrant base URL (defaults to --url / QDRANT_URL)
--api-key <key>Remote API key (defaults to QDRANT_API_KEY)
--shard-id <n>Remote shard to stream; required for multi-shard collections
--forceReplace an existing local collection (verified before the swap)
--jsonMachine-readable result

Shard discovery: for a single-shard collection the shard id is found automatically via GET /collections/{c}/cluster. A collection with more than one shard fails closed with QQL-SNAPSHOT-SHARD unless --shard-id is given — a qdrant-edge collection is exactly one shard, so you seed one shard per device (this pairs with the per-device shard pattern for multi-tenant sources).

An existing local collection is never overwritten without --force, and the replacement only happens after the snapshot downloads and verifies. Failures leave the previous collection untouched, and with --json they emit a structured {ok: false, operation: "edge-bootstrap", collection, message} on stdout before exiting non-zero. The same command is exposed as an #[ignore] integration test: cargo test -p qql-cli --features edge --test edge_bootstrap -- --ignored.

qql config edge writes <config-dir>/edge.json (default config directory is ~/.qql, file written with 0600 permissions). It is a patch update: only the flags you pass are written, and every key you did not set — including keys written by a newer version — is preserved. Against an existing file the merged configuration is validated as a whole, so a persisted --embedder http keeps its persisted --embed-url. After saving it prints:

Saved edge configuration to /home/you/.qql/edge.json
Use it with: qql --edge exec "SHOW COLLECTIONS"
FlagDefaultPurpose
--data-dir <dir>~/.qql/edge-dataDirectory for persistent qdrant-edge data
--in-memoryoffKeep payloads in memory instead of persisting them to disk (sets on_disk_payload=false)
--on-diskonPersist payloads to disk (flips a persisted --in-memory config back)
--wal-segment-mb <n>qdrant-edge 32 MiBWAL segment capacity in MiB. qdrant-edge pre-allocates each segment to this size, which otherwise dominates the on-disk footprint of small embedded shards. Seeds new shards (and shards without a persisted capacity); an already-persisted value wins on reopen. Must be greater than zero; also exposed by the Python/Node edge SDKs (qdrant-edge 0.8's own Python binding cannot set it)
FlagDefaultPurpose
--embedder fastembed|httpfastembedLocal ONNX inference or an OpenAI-compatible endpoint
--model <name>BGESmallENV15 (384-d)Dense model name or alias
--sparse-model <name>local Qdrant-compatible BM25Offline sparse model (splade, bge-m3)
--multi-model <name>noneOffline multivector / ColBERT model (bge-m3)
--image-model <name>noneOffline CLIP vision model (clip-vision)
--reranker-model <name>noneOffline cross-encoder (bge-reranker-base)
--cache-dir <dir>fastembed defaultDirectory for downloaded models
--show-download-progressoffShow Hugging Face download progress bars (--no-show-download-progress flips a persisted config back)

These apply when --embedder http is selected. Storage and search stay local; only embeddings go over the network.

FlagDefaultPurpose
--embed-url <url>none (required for http)OpenAI-compatible embedding endpoint
--embed-key <key>emptyBearer token (EMBED_KEY)
--embed-model <name>nomic-embed-textModel name sent in the request body
--embed-dim <n>768Expected output dimension
--multi-embed-url / --multi-embed-key / --multi-embed-model / --multi-embed-dimnoneOptional multi/ColBERT endpoint (dim 0 skips the dimension check)
--image-embed-url / --image-embed-key / --image-embed-model / --image-embed-dimnoneOptional image/CLIP endpoint (dim 0 uses the dense dimension)

Validation rules: --embedder must be fastembed or http; http requires --embed-url; --embed-dim must be greater than zero; and --wal-segment-mb must be greater than zero when set.

Every qql config edge setting can be overridden per invocation via environment. Edge-specific variables start with QQL_EDGE_; the HTTP embedder reuses the same variables as remote execution.

VariableOverridesNotes
QQL_EDGE_DATA_DIR--data-dirData directory for qdrant-edge storage
QQL_EDGE_EMBEDDER--embedderfastembed or http
QQL_EDGE_MODEL--modelDense model name or alias
QQL_EDGE_SPARSE_MODEL--sparse-modelOffline sparse model
QQL_EDGE_MULTI_MODEL--multi-modelOffline multi/ColBERT model
QQL_EDGE_IMAGE_MODEL--image-modelOffline CLIP vision model
QQL_EDGE_RERANKER_MODEL--reranker-modelAlso falls back to RERANK_MODEL
QQL_EDGE_CACHE_DIR--cache-dirModel download cache directory
QQL_EDGE_ON_DISK--in-memorytrue/false/1/0 — payloads on disk
QQL_EDGE_WAL_SEGMENT_MB--wal-segment-mbWAL segment capacity in MiB (integer > 0); seeds shards without a persisted capacity
EMBED_URL--embed-urlHTTP embedding endpoint
EMBED_KEY--embed-keyBearer token
EMBED_MODEL--embed-modelModel name
EMBED_DIM--embed-dimOutput dimension (integer)
MULTI_EMBED_URL / MULTI_EMBED_KEY / MULTI_EMBED_MODEL / MULTI_EMBED_DIM--multi-embed-*Multi/ColBERT endpoint
IMAGE_EMBED_URL / IMAGE_EMBED_KEY / IMAGE_EMBED_MODEL / IMAGE_EMBED_DIM--image-embed-*Image/CLIP endpoint
One-shot edge override
QQL_EDGE_DATA_DIR=/tmp/ephemeral QQL_EDGE_MODEL=all-minilm-l6-v2 \
qql --edge exec "QUERY 'hi' FROM docs USING dense LIMIT 3"

qql --edge doctor performs a real edge init (config load, model resolution, shard open) and then runs SHOW COLLECTIONS against it. It prints a summary of which embedding slots are configured and actionable hints:

Connected to the local edge backend (healthy)
collections: edge backend (local, 2)
collection 'docs': 300 points, 0 indexed — qdrant-edge only indexes during optimize; run `qql edge optimize docs` after bulk writes (segments below indexing_threshold stay brute-force)
Hosts: dense=true multi=false image=false cross_rerank=false
dense_model: BGESmallENV15
hint: ColBERT / AS MULTI / multivector RERANK needs multi_model or multi_embedding_* config
hint: IMAGE / CLIP vision needs image_model or image_embedding_* config
hint: CROSS RERANK needs reranker_model or rerank_endpoint / rerank_model
hint: edge has no SHARD routing or shard-key DDL; ALTER COLLECTION covers HNSW/optimizers only

qql check --edge "<statement>" adds the same per-collection readout as an edge-indexing stage (ok when indexed ≥ points, warn with the optimize nudge when it lags; warnings never fail the check).

The hints are guidance, not failures — the backend is healthy. If a configured model cannot be loaded (for example an unknown name), doctor reports the init error instead. The JSON form is available via qql --edge doctor --json, which emits backend, dense/multi/image/cross_rerank booleans, the resolved model names, the hints array, and an edge_indexing array of per-collection {collection, points_count, indexed_vectors_count, segments_count, nudge}.

  • File: <config-dir>/edge.json where the config dir is ~/.qql
  • Permissions: 0600 on Unix (contains embedding API keys when using the HTTP embedder)
  • Default data dir: <config-dir>/edge-data

For what happens inside the data directory, see persistence.