CLI Reference
Every nucladb-cli command, with real recorded output.
Commands: ping, create-tenant, tenants, set-quota, delete-tenant, insert, batch-upsert, get, update-metadata, list, count, search, delete, plus quickstart (scripted demo), shell completion, and a -json output flag.
Connecting: talks to localhost:9090 by default; override via the NUCLADB_ADDR env var. For a server run with -api-keys, set NUCLADB_API_KEY; set NUCLADB_TLS=1 if it serves TLS.
Multi-tenancy: every data command accepts -tenant; omitting it uses the reserved default tenant (no quota). A non-default tenant must be created first via create-tenant.
Install + quickstart
curl -fsSL https://raw.githubusercontent.com/Rakshit-gen/NuclaDB/main/install.sh | sh
nucladb-cli quickstartInstalls both binaries (go install under the hood) and starts a throwaway local nucladbd: a temp data dir, free local ports, dim=4 and metric=l2. It then runs a scripted insert/search demo and leaves the server running until Ctrl+C.
Manual insert / search
export NUCLADB_ADDR=127.0.0.1:<port from quickstart's output>
nucladb-cli insert -id=1 -vector=1,0,0,0 -meta=team=search
nucladb-cli search -vector=1,0,0,0 -top-k=5Multi-tenancy + filtering
A real recorded session, showing tenant isolation: the same id (1) exists independently under default and acme, with completely different data and no collision.
$ nucladb-cli create-tenant -id=acme -max-vectors=1000000
created tenant "acme"
$ nucladb-cli insert -id=1 -vector=1,0,0,0 -meta=team=search
inserted id=1
$ nucladb-cli insert -id=1 -tenant=acme -vector=1,0,0,0 -meta=who=acme
inserted id=1
$ nucladb-cli search -vector=1,0,0,0 -top-k=3
1 score=0.000000 map[team:search]
3 score=2.000000 map[]
2 score=2.000000 map[team:infra]
$ nucladb-cli search -vector=1,0,0,0 -top-k=3 -filter=team=infra
2 score=2.000000 map[team:infra]
$ nucladb-cli search -vector=1,0,0,0 -top-k=5 -tenant=acme
1 score=0.000000 map[who:acme]create-tenant also takes -dim and -metric (cosine, l2, dot), so tenants on one server can hold different vector sizes and metrics. Both default to the server's own -dim and -metric.
Richer filters
-where takes key:op or key:op:value, with op one of eq ne in not_in gt gte lt lte exists. in/not_in take comma-separated values, and the numeric ops compare as numbers. Repeat it to AND clauses:
$ nucladb-cli search -vector=1,0,0,0 -where=year:gte:2024 -where=team:in:search,infra
2 score=2.000000 map[team:infra year:2025]Reading and editing vectors
$ nucladb-cli get -id=2
2 [0 1 0 0] map[team:ads year:2025]
$ nucladb-cli update-metadata -id=2 -meta=team=infra -meta=year=2025
updated id=2
$ nucladb-cli list
1
2
$ nucladb-cli count
2update-metadata replaces all of a vector's metadata and leaves the vector alone.
Tenant admin
$ nucladb-cli tenants
default vectors=2 dim=4 metric=l2 max_vectors=0 max_qps=0
t2 vectors=0 dim=2 metric=cosine max_vectors=5 max_qps=0
$ nucladb-cli set-quota -id=t2 -max-vectors=5
set quota for "t2"
$ nucladb-cli delete-tenant -id=t2
deleted tenant "t2"On a server with API keys, these need an admin key.
Quota / rate-limit errors
$ nucladb-cli insert -id=4 -tenant=acme -vector=1,1,1,1
nucladb-cli: rpc error: code = ResourceExhausted desc = engine: tenant storage quota exceeded
$ nucladb-cli insert -id=5 -tenant=doesnotexist -vector=1,1,1,1
nucladb-cli: rpc error: code = NotFound desc = engine: tenant not foundWith -api-keys on the server, a missing key gets Unauthenticated and a key that doesn't cover the tenant gets PermissionDenied.
Tenant quotas, dimension and metric are saved in the tenant's data directory and survive a restart.
Python client
pip install ./clients/pythonInstalls the nucladb library and a nucladb CLI covering the core commands (the newer read and tenant-admin operations are library methods):
from nucladb import Client, DistanceMetric
with Client("localhost:9090", api_key="", tls=False) as db:
db.insert("1", [1.0, 0.0, 0.0, 0.0], metadata={"team": "search", "year": "2025"})
for match in db.search([1.0, 0.0, 0.0, 0.0], top_k=3, metric=DistanceMetric.L2):
print(match.id, match.score, match.metadata)
db.search([1.0, 0.0, 0.0, 0.0], where=[("year", "gte", 2024), ("team", "in", ["search", "ads"])])
db.get("1") # (vector, metadata), or None
db.update_metadata("1", {"team": "infra"})
ids = list(db.list())
db.count()
db.create_tenant("acme", dim=384, metric=DistanceMetric.COSINE)
db.set_quota("acme", max_qps=50)
db.list_tenants()
db.delete_tenant("acme")Its smoke test builds the real Go nucladbd binary and runs it as a subprocess, so it's an actual end-to-end test, not a mocked one.