How to use Cypher with HydraDB
Quickstart
hydradb_graph_query, hydradb_graph_collections, hydradb_graph_admin).
Authentication
Every request needs your HydraDB API key:403. Your databases are visible only to
your organization: another organization’s databases look like names that
don’t exist, and MATCH (n) RETURN n returns only your own nodes.
Endpoints
POST /byog/databases - create a database
A database groups your collections. BYOG databases are created only through
this endpoint, and they are ready immediately. Creating a name that already
exists returns 409.
POST /byog/query - run Cypher
- Each collection is an isolated graph. A query runs against one collection and cannot see data in any other.
- Collections are created automatically on the first write. Reading a collection that doesn’t exist yet returns zero rows.
- Pass user data through
paramsinstead of building it into the query string. - Collection names can use letters, digits,
_and-, must start with a letter or digit, and can be up to 64 characters long.
GET /byog/collections - list collections
An unknown database returns 404.
DELETE /byog/collections - drop one collection
Drops the collection and all its data. Deleting a collection that does not
exist also succeeds.
DELETE /byog/databases - drop a database
Drops the database and every collection in it.
Supported Cypher
Essentially all of openCypher is supported. Only server-side procedures and file loading are excluded. 1. Modelling and CRUD- Create, read, update and delete:
CREATE,MATCH,MERGE,SET,REMOVE,DELETE/DETACH DELETE - Pattern matching,
WHEREfilters, aggregation,ORDER BY/SKIP/LIMIT UNWINDandWITHpipelines- Indexes:
CREATE INDEX FOR (n:Label) ON (n.prop) CALL { ... }subqueries
- Multi-hop patterns - chain relationships in one
MATCH:MATCH (a:Person)-[:KNOWS]->(b)-[:WORKS_AT]->(c:Company) RETURN c.name. - Variable-length traversal - follow a relationship a bounded or unbounded
number of hops with
*:MATCH (a:Person {name:$n})-[:KNOWS*1..4]->(reach) RETURN DISTINCT reach.name. - Neighborhood expansion - a node’s edges and neighbors in any direction:
MATCH (p:Person {name:$n})-[r]-(nbr) RETURN type(r) AS rel, nbr.name AS neighbor. - Path finding -
shortestPathreturns the full path (nodes and edges in traversal order), not just the endpoints. - Directed, typed, filtered traversal - outgoing (
->), incoming (<-) or either (-) edges, filtered by relationship type and by node or edge properties anywhere along the walk.
- Existence checks are bare pattern predicates -
MATCH (p:Person) WHERE (p)-[:KNOWS]->() RETURN p.name AS name. TheEXISTS { ... }block form and theexists()function are not accepted. shortestPathgoes in aRETURNorWITHclause (notMATCH p = …) and the traversal must be directed.
Common Cypher queries
Load the sample graph - Five people, two companies, and theKNOWS / WORKS_AT edges between them.
Result
Result
u1 doesn’t exist.
Result
Result
Result
Result
Result
Result
KNOWS edges.
Result
Result
Result
Result
Result
Result
Result
Result
ext_id. A write with no RETURN returns an empty list.
Result
Result
Result
Result
Response format
Rows come back indata - one object per result row, keyed by your RETURN
aliases:
- Alias every column you read (
RETURN n.name AS name). An unaliased column is keyed by its expression text ("n.name"). - A write with no
RETURNsucceeds withdata: [].
- Nodes and relationships are flat objects: their properties plus the keys
shown above. A stored property with one of those names (
id,labels,relation,source_node_id,target_node_id) is hidden in the response - alias it (RETURN n.id AS my_id). idis internal: it can be reused after deletes and does not survive an export/re-import. Key your data on a property you own (ext_id,email, …).- Integers are 64-bit. Values beyond 2⁵³ lose precision in languages that parse JSON numbers as doubles - return them as strings.
Using results in your code
A minimal client
Wrap the endpoint once. Success puts rows indata; errors are wrapped in
detail.
Reading rows
Pagination
Result sets past the deployment cap are silently truncated, so page any read that could be large. A stableORDER BY keeps pages consistent:
Bulk loading
Chunk rows to stay inside the 256 KiB body cap and the 30 s write budget;MERGE on your own key makes the load re-runnable after a failure:
Handling failures
400- the message tells you what to fix: your Cypher (compiler feedback is passed through) or a query that needsLIMIT/an index (budget timeout). Retrying unchanged will fail identically.429/500- transient; retry with backoff. Writes built onMERGE(as above) are safe to retry; bareCREATEbatches are not idempotent, so a retried chunk can duplicate nodes.
Errors and limits
Errors
Errors
Errors come back with
success: false and the reason in error (also
mirrored in detail):Limits and timeouts
Limits and timeouts
A query counts as a write (and gets the larger budget) when it contains
any write clause -
CREATE, MERGE, SET, DELETE, REMOVE, FOREACH.- Paginate anything potentially large:
ORDER BY … SKIP $offset LIMIT $page. Without anORDER BY, rows dropped at the result-set cap are arbitrary. - Chunk bulk imports into
UNWIND $rowsbatches sized to finish inside the 30 s write budget (and the 256 KiB body cap). - Create indexes for properties you filter on -
CREATE INDEX FOR (n:Person) ON (n.name). A slow read usually needs one.
Migrating from Neo4j or another Cypher-compatible database
Most application Cypher from Neo4j, Memgraph, or any other Cypher-compatible database ports directly. The differences you are most likely to notice:- Procedure calls (for example Neo4j’s
CALL db.*/CALL apoc.*) are not available - the equivalents are either plain Cypher or not part of the supported surface. LOAD CSVis not available - batch data in throughparams.- Internal node ids are not portable - migrate using your own key properties,
for example
UNWIND $rows AS row MERGE (n:Person {ext_id: row.ext_id}) SET n += row.
HydraGraph client. Any source you can
read nodes and relationships from works the same way. It loads nodes first,
then relationships matched on your own key. Cypher doesn’t allow a
relationship type as a parameter, so it writes one batch per type:
Using BYOG without Cypher
To use your own entities and relations for a document or memory instead of HydraDB’s LLM extraction, pass agraph_payload on
POST /context/ingest. It is a
JSON map keyed by source id (a document_metadata id, an app_knowledge
id, or a memory id):
- Replaces extraction for each keyed source; the source is still chunked
and embedded. Relations surface in
/querygraph_context(taggedorigin: "byog") - no query-side changes. - Persists across re-ingest - re-ingesting without a
graph_payloadre-applies the stored graph; sending a new one replaces it. - Limits - ≤ 5,000 entities, ≤ 10,000 relations, ≤ 500 relations per
entity; oversized payloads return
400. A key matching no source in the request is rejected with400. - Whole-graph only: no per-triple updates, and relations link to their best-matching chunk even when the match is weak.
graph_payload field reference
for the full shape.