qql-go is a portable command-line interface for operating, inspecting, testing, and automating Qdrant vector databases.
It gives developers, scripts, CI pipelines, support workflows, and AI agents one deterministic command surface for common Qdrant operations without writing SDK code for every task.
Use the Qdrant SDK when you are building application logic.
Use qql-go when you need repeatable commands, stable JSON output, version-controlled .qql scripts, and a binary that can run anywhere.
qql-go is an independent Go implementation inspired by the original pavanjava/qql, with a focus on portability, operational workflows, and automation-friendly output.
qql-go supports common Qdrant operations including:
- collection management
- collection quantization
- payload index creation
- document insertion
- vector and payload update
- point retrieval and scroll pagination
- dense, sparse, and hybrid retrieval
- search pagination, score thresholds, and cross-collection lookup
- grouped retrieval
- recommendation by example IDs
- rerank retrieval
- explain plans
- script execution
- collection dump
- filter-based delete
It is designed for two modes of use:
- Human-readable CLI output for local debugging, diagnostics, and exploration
- Stable JSON output for scripts, CI jobs, automation pipelines, and agents
Qdrant already has excellent SDKs. qql-go is not trying to replace them.
The SDK is the right tool for application code.
qql-go exists for the workflows where SDK code is not the ideal artifact:
- running CI smoke tests against a Qdrant instance
- checking collection state from a terminal
- debugging retrieval behavior during support sessions
- executing version-controlled
.qqlscripts - automating maintenance tasks from shell scripts or cron jobs
- giving AI agents a constrained command interface instead of arbitrary SDK code generation
In short:
Use the SDK to build your application.
Useqql-goto operate, inspect, test, and automate Qdrant.
qql-go is strongest in operational and automation workflows:
-
CI and smoke tests
Validate collection setup, inserts, filters, and search behavior from a single binary. -
Support and debugging
Share exact commands that others can copy, run, and audit. -
Version-controlled database operations
Store.qqlscripts in git for seeding, validation, cleanup, and repeatable maintenance. -
Retrieval diagnostics
Compare dense, sparse, hybrid, and rerank behavior through readable commands. -
Agent and scripting workflows
Use--jsonoutput as a stable interface for agents, shell scripts,jq, and automation pipelines.
qql-go is not:
- an ORM
- a replacement for the Qdrant SDK in application code
- a full SQL database layer over Qdrant
- a general-purpose application framework
It is a compact operational command interface for Qdrant.
The goal is not to hide Qdrant behind another abstraction.
The goal is to make Qdrant operations portable, repeatable, auditable, and easy to automate.
Install the latest release on macOS or Linux:
curl -fsSL https://raw.githubusercontent.com/srimon12/qql-go/main/install.sh | shInstall a specific version:
curl -fsSL https://raw.githubusercontent.com/srimon12/qql-go/main/install.sh | VERSION=v0.2.0 shThe Unix installer defaults to ~/.local/bin/qql-go. Override with INSTALL_DIR=/your/bin/path when needed.
Install on Windows with PowerShell:
irm https://raw.githubusercontent.com/srimon12/qql-go/main/install.ps1 | iexinstall the bundled QQL skill for agent use:
npx skills add srimon12/qql-go --skill qql-skillgit clone https://github.com/srimon12/qql-go.git
cd qql-go
go build -o qql-go ./cmd/qql-goConnect to Qdrant Cloud for text insert and text search:
qql-go connect --url https://<your-cluster>.qdrant.io --secret <your-api-key>Or connect to a local/self-hosted Qdrant instance for non-inference operations:
qql-go connect --url http://localhost:6334Or connect in external/local inference mode with an OpenAI-compatible embeddings API:
qql-go connect \
--url http://localhost:6334 \
--inference-mode external \
--embedding-endpoint https://api.openai.com/v1/embeddings \
--embedding-key <embedding-api-key> \
--embedding-model text-embedding-3-smallRun a simple query:
qql-go exec "SHOW COLLECTIONS"
qql-go exec "SHOW COLLECTION docs"Explain a query without executing it:
qql-go explain "SEARCH docs SIMILAR TO 'vector db' LIMIT 5 USING HYBRID"Check saved connection health:
qql-go doctorUse the CLI directly:
qql-go exec "CREATE COLLECTION docs HYBRID"
qql-go exec "CREATE COLLECTION docs HYBRID QUANTIZE TURBO BITS 2 ALWAYS RAM"
qql-go exec "INSERT INTO COLLECTION docs VALUES {'text': 'Qdrant stores vectors', 'topic': 'search'} USING HYBRID"
qql-go exec "SEARCH docs SIMILAR TO 'vector database' LIMIT 5 USING HYBRID"
qql-go exec "SEARCH docs SIMILAR TO 'vector database' LIMIT 5 USING HYBRID FUSION 'dbsf'"
qql-go exec "SEARCH docs SIMILAR TO 'bm25 keyword' LIMIT 5 USING SPARSE"
qql-go exec "SEARCH docs SIMILAR TO 'vector database' LIMIT 5 USING HYBRID RERANK"
qql-go exec "SEARCH docs SIMILAR TO 'vector database' LIMIT 5 USING HYBRID GROUP BY topic GROUP_SIZE 2"
qql-go exec "SHOW COLLECTION docs"
qql-go exec "SELECT * FROM docs WHERE id = 'pt-1'"
qql-go exec "SCROLL FROM docs LIMIT 10"
qql-go exec "UPDATE docs SET PAYLOAD WHERE id = 'pt-1' {'topic': 'retrieval'}"Start the interactive shell:
qql-goor:
qql-go replREPL shortcuts:
help,?,\hexplain <query>exit,quit,\q,:q
For automation, do not parse human prose output.
Use compact structured output:
qql-go exec --quiet --json "<query>"
qql-go explain --quiet --json "<query>"
qql-go doctor --quiet --json
qql-go connect --quiet --json --url <url> [--secret <secret>]
qql-go disconnect --quiet --json
qql-go version --quiet --jsonRecommended agent examples:
qql-go exec --quiet --json "SHOW COLLECTIONS"
qql-go exec --quiet --json "SHOW COLLECTION docs"
qql-go explain --quiet --json "SEARCH docs SIMILAR TO 'vector db' LIMIT 5 USING HYBRID"
qql-go doctor --quiet --jsonOutput contract notes:
--jsonenables structured output--quiet --jsonemits compact JSONqql-go explain --quiet "<query>"prints raw plan textqql-go connect --jsonandqql-go connect --quietdo not enter REPLqql-go versionprints the current version
- Qdrant collection management
- Hybrid search and rerank exploration
- Agent-driven retrieval workflows
- Scripted demos and reproducible queries
Important behavior in the current Go build:
- cloud mode uses Qdrant Cloud inference for text
INSERTand textSEARCH ... SIMILAR TO ... - local and external modes generate dense and sparse vectors client-side through an OpenAI-compatible embeddings API
- use
--embedding-keywhen the embedding provider requires bearer auth RERANKis still cloud-only in this buildSELECT,SCROLL,DELETE, andRECOMMENDoperate on stored vectors and work in every inference mode- self-hosted/local Qdrant works well for management operations such as
SHOW,CREATE,DROP,CREATE INDEX,SELECT,SCROLL, andDELETE - collections auto-create on insert when missing
textis required inINSERT ... VALUES {...}- keys in
VALUES {...}may be bare identifiers or quoted strings; quote them when they contain spaces or punctuation
Put differently:
- use Qdrant Cloud if you want the hosted inference path or rerank
- use local/external mode if you want client-side embeddings against any Qdrant instance
- use local/self-hosted freely for management operations even without inference
Supported statements:
CREATE COLLECTION <name>
CREATE COLLECTION <name> HYBRID
CREATE COLLECTION <name> HYBRID RERANK
CREATE COLLECTION <name> USING MODEL '<model>'
CREATE COLLECTION <name> QUANTIZE SCALAR
CREATE COLLECTION <name> QUANTIZE SCALAR QUANTILE <0.0-1.0>
CREATE COLLECTION <name> QUANTIZE SCALAR QUANTILE <0.0-1.0> ALWAYS RAM
CREATE COLLECTION <name> QUANTIZE BINARY
CREATE COLLECTION <name> QUANTIZE BINARY ALWAYS RAM
CREATE COLLECTION <name> QUANTIZE PRODUCT
CREATE COLLECTION <name> QUANTIZE PRODUCT ALWAYS RAM
CREATE COLLECTION <name> QUANTIZE TURBO
CREATE COLLECTION <name> QUANTIZE TURBO BITS <1|1.5|2|4>
CREATE COLLECTION <name> QUANTIZE TURBO BITS <1|1.5|2|4> ALWAYS RAM
CREATE COLLECTION <name> WITH HNSW { payload_m: <n> }
DROP COLLECTION <name>
SHOW COLLECTIONS
SHOW COLLECTION <name>
CREATE INDEX ON COLLECTION <name> FOR <field> TYPE keyword
CREATE INDEX ON COLLECTION <name> FOR <field> TYPE integer
CREATE INDEX ON COLLECTION <name> FOR <field> TYPE float
CREATE INDEX ON COLLECTION <name> FOR <field> TYPE bool
CREATE INDEX ON COLLECTION <name> FOR <field> TYPE uuid
CREATE INDEX ON COLLECTION <name> FOR <field> TYPE keyword WITH { is_tenant: true, on_disk: true, enable_hnsw: false }
CREATE INDEX ON COLLECTION <name> FOR <field> TYPE text WITH { tokenizer: 'word', min_token_len: 2, max_token_len: 20, lowercase: true }
INSERT INTO COLLECTION <name> VALUES {...}
INSERT INTO COLLECTION <name> VALUES {...} USING MODEL '<model>'
INSERT INTO COLLECTION <name> VALUES {...} USING HYBRID
INSERT INTO COLLECTION <name> VALUES {...} USING HYBRID DENSE MODEL '<model>' SPARSE MODEL '<model>'
INSERT INTO COLLECTION <name> VALUES {...} USING HYBRID SPARSE MODEL '<model>'
INSERT BULK INTO COLLECTION <name> VALUES [{...}, {...}]
INSERT BULK INTO COLLECTION <name> VALUES [{...}, {...}] USING HYBRID
SEARCH <name> SIMILAR TO '<query>' LIMIT <n>
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> OFFSET <n>
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> SCORE THRESHOLD <float|int>
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> LOOKUP FROM <collection> [VECTOR '<name>']
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> USING MODEL '<model>'
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> USING HYBRID
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> USING HYBRID FUSION 'rrf|dbsf'
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> USING HYBRID DENSE MODEL '<model>' SPARSE MODEL '<model>'
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> USING SPARSE
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> USING SPARSE MODEL '<model>'
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> WHERE <filter>
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> EXACT
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> WITH { hnsw_ef: <n>, exact: true|false, acorn: true|false, indexed_only: true|false }
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> WITH { quantization: { ignore: true|false, rescore: true|false, oversampling: <n> } }
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> WITH { mmr_diversity: <0..1>, mmr_candidates: <n> }
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> USING HYBRID WITH { mmr_diversity: <0..1>, mmr_candidates: <n> }
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> RERANK
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> RERANK MODEL '<model>'
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> USING HYBRID RERANK
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> USING SPARSE RERANK
SEARCH <name> SIMILAR TO '<query>' LIMIT <n> GROUP BY <field> [GROUP_SIZE <n>]
SELECT * FROM <name> WHERE id = '<uuid>'
SELECT * FROM <name> WHERE id = <integer>
SCROLL FROM <name> LIMIT <n>
SCROLL FROM <name> WHERE <filter> LIMIT <n>
SCROLL FROM <name> AFTER '<point_id>' LIMIT <n>
SCROLL FROM <name> WHERE <filter> AFTER <point_id> LIMIT <n>
RECOMMEND FROM <name> POSITIVE IDS (<id>, ...) LIMIT <n>
RECOMMEND FROM <name> POSITIVE IDS (<id>, ...) NEGATIVE IDS (<id>, ...) LIMIT <n>
RECOMMEND FROM <name> POSITIVE IDS (<id>, ...) STRATEGY '<strategy>' LIMIT <n>
RECOMMEND FROM <name> POSITIVE IDS (<id>, ...) LIMIT <n> OFFSET <n>
RECOMMEND FROM <name> POSITIVE IDS (<id>, ...) LIMIT <n> SCORE THRESHOLD <float|int>
RECOMMEND FROM <name> POSITIVE IDS (<id>, ...) LOOKUP FROM <collection> [VECTOR '<name>'] USING '<vector_name>' LIMIT <n>
DELETE FROM <name> WHERE id = '<uuid>'
DELETE FROM <name> WHERE id = <integer>
DELETE FROM <name> WHERE <field> = '<value>'
qql-go execute <script.qql>
qql-go execute --stop-on-error <script.qql>
qql-go dump <collection> <output.qql>
qql-go dump --batch-size <n> <collection> <output.qql>
`qql-go explain <statement>`Dense search:
- use plain
SEARCH - use
USING MODEL '<model>'when you want to pin the dense model - add
OFFSET <n>for flat search pagination - add
SCORE THRESHOLD <float|int>to drop low-score matches - add
LOOKUP FROM <collection> [VECTOR '<name>']for cross-collection vector lookup - default dense model:
sentence-transformers/all-minilm-l6-v2
Collection quantization:
- use
QUANTIZE SCALARfor the defaultint8compression path - use
QUANTIZE SCALAR QUANTILE <0..1>when you want explicit scalar calibration - use
QUANTIZE BINARYfor more aggressive compression - use
QUANTIZE PRODUCTfor fixedx4product quantization - use
QUANTIZE TURBO [BITS <1|1.5|2|4>]for stronger compression with better recall than binary - add
ALWAYS RAMwhen quantized vectors should stay pinned in memory
Hybrid search:
- use
USING HYBRIDwhen exact terms and semantic similarity both matter; this usesRRFby default - use
FUSION 'dbsf'when you want the DBSF hybrid fusion strategy instead of the default RRF - use
WITH { mmr_diversity, mmr_candidates }with hybrid search when you want diversity on the dense leg before fusion - combine
GROUP BYwith hybrid search when you need grouped top results; do not combine grouped search withOFFSET - default sparse model:
qdrant/bm25
Sparse-only search:
- use
USING SPARSEwhen the request is primarily keyword retrieval - use
USING SPARSE RERANKwhen sparse recall is good but top ordering needs cloud rerank
Point access:
- use
SELECTwhen you already know the exact point ID - use
SCROLLwhen you need pagination or to browse points page by page
Rerank:
- use
RERANKwhen retrieval is okay but ordering needs improvement - default rerank model:
answerdotai/answerai-colbert-small-v1 - requires a collection created with
HYBRID RERANK
Search-time tuning:
EXACTWITH { hnsw_ef: <n> }WITH { exact: true|false }WITH { acorn: true|false }WITH { indexed_only: true|false }WITH { quantization: { ignore, rescore, oversampling } }WITH { mmr_diversity: <0..1>, mmr_candidates: <n> }for dense search and the dense leg of hybrid search
Supported predicates:
=!=>>=<<=BETWEEN ... AND ...IN (...)NOT IN (...)- boolean literals:
true,false IS NULLIS NOT NULLIS EMPTYIS NOT EMPTYMATCHMATCH ANYMATCH PHRASE
Supported logical operators:
ANDORNOT- parentheses
Examples:
SEARCH articles SIMILAR TO 'deep learning' LIMIT 10 WHERE year >= 2020
SEARCH articles SIMILAR TO 'retrieval' LIMIT 10 WHERE status IN ('published', 'reviewed')
SEARCH articles SIMILAR TO 'search' LIMIT 10 WHERE title MATCH PHRASE 'semantic search'
SEARCH docs SIMILAR TO 'incident' LIMIT 10 WHERE (team = 'search' OR team = 'infra') AND severity >= 3If you filter heavily, create payload indexes first.
- CHANGELOG.md for the latest user-facing changes
The repo now ships first-class operational examples under examples/README.md.
If you want the single strongest example first, start with examples/release-validation/: it runs read-only retrieval regression checks against an existing Qdrant collection, validates JSON artifacts, and fits naturally into CI without reseeding the corpus.
Use them to showcase the workflows qql-go is strongest at:
- retrieval regression CI
- retrieval debugging and runbooks
- vertical benchmark workflows such as medical retrieval
The agent-oriented helper demos still live under skills/qql-skill/scripts/, but they are now secondary to the public examples/ surface.
This repo publishes installable skills from skills/.
List available skills:
npx skills add srimon12/qql-go --listInstall the bundled QQL skill:
npx skills add srimon12/qql-go --skill qql-skillPrebuilt binaries are published on GitHub Releases for:
- Windows
- Linux
- macOS
The repo also ships direct install scripts:
Config is stored at:
~/.qql/config.json
- CONTRIBUTING.md for contributors
- docs/DEVELOPMENT.md for maintainers and release workflow details
- CHANGELOG.md for user-facing changes
- docs/releases/0.2.0.md for the current release note
qql-go/
├── cmd/qql-go/
├── internal/ast/
├── internal/cli/
├── internal/config/
├── internal/errors/
├── internal/filters/
├── internal/lexer/
├── internal/output/
├── internal/parser/
├── internal/repl/
├── skills/qql-skill/
├── install.sh
├── install.ps1
└── README.md
go test ./...
go build ./cmd/qql-go