Documentation Index
Fetch the complete documentation index at: https://docs.helix-db.com/llms.txt
Use this file to discover all available pages before exploring further.
For the complete documentation index optimized for AI agents, see llms.txt.
readBatch() only accepts read traversals — the TypeScript type system rejects any
mutating step. To create nodes, add edges, or update properties, switch to
writeBatch().
Inside a writeBatch, every varAs may chain any read step or any write step. The
typestate machinery flips into “write” mode the moment a mutation appears, so a write
batch can also do plain reads (look up an existing user, then update them).
Adding nodes
g().addN(label, properties) inserts a new node and emits a single-item stream — the
new node. Property values can be passed as a plain object (most common) or as a list
of [name, PropertyInput] tuples (matches the Rust vec![("name", value)] shape).
- The
propertiesarray preserves insertion order —Map-style, notObject-style. - Each value is wrapped in a
PropertyInput. A literal becomes{"Value": {"String": ...}}; a parameter becomes{"Expr": {"Param": "..."}}(covered in Parameters & bundles). - The result of
addNis a node stream, so the same chain can keep going — here,.project([...])collects the new id.
Adding edges between bound nodes
addE joins two nodes by label. The to argument is a NodeRef — most often
NodeRef.var("...") pointing at a node bound earlier in the same batch.
writeBatch shares the same transaction — either all three writes
above land, or none do. There is no manual BEGIN/COMMIT; see
Transactions for details.
Updating properties
Two single-property steps update an existing node or edge:.setProperty(name, value)— set or overwrite..removeProperty(name)— unset.
.count() to confirm how many
rows were touched.
request_type is "write". Any mutation step anywhere in the AST
makes the request a write — .toDynamicJson on a writeBatch picks the right value
automatically.
Deleting nodes and edges
Three drop steps cover the common cases. All require an anchored stream first..drop()— delete the current nodes (and the edges they participate in)..dropEdge(to)— from a node stream, delete edges going to a specific other node (NodeRef). Optionally label-scoped via.dropEdgeLabeled(to, label)..dropEdgeById(EdgeRef)— delete edges by id; the safe choice when the same node pair could have multiple parallel edges (multigraph mode).
.drop() to remove a node entirely — .nWithLabel("Post").where(...).drop()
will remove matching posts plus every edge incident to them.
Conditional writes with varAsIf
Sometimes a write should only run when a previous step did or did not produce
results. .varAsIf(name, condition, traversal) attaches a BatchCondition to a step
so it only executes when the named variable is non-empty, empty, or has at least N
items.
The most common pattern is upsert: load the row, update if found, create if not.
BatchCondition.varNotEmpty(name)— run whennameproduced ≥ 1 result.BatchCondition.varEmpty(name)— run whennameproduced 0 results.BatchCondition.varMinSize(name, n)— run whennameproduced ≥nresults.BatchCondition.prevNotEmpty()— same asvarNotEmptybut for the immediately preceding step, useful when you don’t want to name it.
Next Steps
Vector and text search
Create indexes, run vector / BM25 searches, and traverse from hits.
Advanced patterns
repeat, union, choose, coalesce, optional, forEachParam.