Skip to main content

SQL and Cypher clients

A self-hosted engine speaks the PostgreSQL wire protocol and Bolt, the Neo4j protocol. Existing drivers and tools connect to it directly: psql, node-postgres or psycopg send SQL, and the Neo4j drivers send openCypher. They read and write the same records the SDKs do.

Self-hosted only

RushDB Cloud is reached through the SDKs, the REST API and MCP. The PostgreSQL wire, Bolt and gRPC listeners belong to the self-hosted engine.

InterfaceLanguageGood forNot available
PostgreSQL wireSQLReports, SQL tools, services that already use a PostgreSQL driverTransactions, vector and keyword search, system catalogs
Bolt 5.0openCypherCode and tools written for Neo4jTLS, multitenant servers, vector and keyword search
gRPCAny enabled language, native operationsService meshes; the full engine API over HTTP/2TLS, capability tokens

Search, embeddings, imports and index management go through the SDKs or the engine's HTTP API.

How your data looks​

The examples use the records from the Quick Tutorial: a PROJECT with three TASK records, imported as nested JSON.

RushDBSQLCypher
Label TASKTable task (names are case-insensitive)(:TASK)
Record IDColumn __id_id in a returned node
Property estimateColumn estimate, typed from the stored valuest.estimate
Relationship type KNOWSTable rushdb_edges.knows with __source_id and __target_id-[:KNOWS]->

A nested import links parent and child with the default relationship type __RUSHDB__RELATION__DEFAULT__. In SQL that is the table rushdb_edges."__rushdb__relation__default__"; in Cypher, match it with an untyped arrow -->.

Turn the listeners on​

The PostgreSQL wire listener starts on port 5432 whenever SQL is enabled, which it is by default. Bolt needs a port and the cypher language:

rushdb serve --data-dir ./rushdb-data --token "$RUSHDB_TOKEN" \
--languages sql,cypher --bolt-port 7687

Listing --languages replaces the default set, so name sql to keep the PostgreSQL wire listener. Add --grpc-port 50051 for gRPC. The engine logs the ports it bound: rushdb listening http_port=3000 pgwire_port=5432 grpc_port=0 bolt_port=7687.

SQL over the PostgreSQL wire​

Connect as any user, with the engine token as the password and TLS off:

PGPASSWORD="$RUSHDB_TOKEN" psql "host=127.0.0.1 port=5432 user=rushdb dbname=rushdb sslmode=disable"
SELECT title, estimate FROM task WHERE status = 'pending' ORDER BY estimate DESC;

-- Join tasks to their project through the nested-import relationship
SELECT p.name, count(*) AS tasks
FROM project p
JOIN rushdb_edges."__rushdb__relation__default__" e ON e.__source_id = p.__id
JOIN task t ON t.__id = e.__target_id
GROUP BY p.name;

What to know:

  • Every statement commits on its own. BEGIN, COMMIT and ROLLBACK fail with SQLSTATE 0A000, so run drivers in autocommit mode (psycopg needs autocommit=True). Use SDK transactions for atomic multi-step writes.
  • One statement per query. Multi-statement strings are not supported.
  • No PostgreSQL catalogs. pg_catalog does not exist, so \d in psql and tools that read it do not work. information_schema.tables and information_schema.columns list the tables and their columns.
  • Supported SQL: SELECT with joins, grouping and aggregates, and INSERT, UPDATE and DELETE on label tables. Tested with psql, node-postgres 8, psycopg 3 and tokio-postgres. See SQL for the dialect and limits, and PostgreSQL wire protocol for error codes.

Cypher over Bolt​

Use a bolt:// URL (not neo4j://) and the engine token as the password:

import os
from neo4j import GraphDatabase

driver = GraphDatabase.driver("bolt://127.0.0.1:7687", auth=("rushdb", os.environ["RUSHDB_TOKEN"]))
with driver.session() as session:
pending = session.run(
"MATCH (p:PROJECT)-->(t:TASK) WHERE t.status = $status "
"RETURN p.name AS project, t.title AS title ORDER BY t.estimate DESC",
status="pending",
)
for record in pending:
print(record["project"], record["title"])

# Writes can run in a managed transaction and commit together.
session.execute_write(lambda tx: tx.run(
"CREATE (:TASK {title: $title, status: 'pending', estimate: 4})", title="Add Bolt docs"
).consume())
driver.close()

What to know:

  • Reads see committed data. session.run, execute_read/executeRead and execute_query/executeQuery all work. A read inside execute_write/executeWrite does not see that transaction's own writes until it commits.
  • Nodes come back as maps with _id, __label and the properties, not as driver Node objects. Return properties (RETURN t.title AS title) for typed columns.
  • No TLS and no multitenant servers. Keep Bolt on loopback or behind a proxy that terminates TLS.
  • Tested with the Python neo4j 6.4 and JavaScript neo4j-driver 6.2 drivers. See openCypher for the supported language and Bolt for the protocol details.

gRPC​

rushdb.v1.Database/Execute carries the same request envelope as the HTTP API, so it reaches every operation and language. The gRPC page has the service definition and examples with grpcurl and Rust's tonic.

Security​

The PostgreSQL wire, Bolt and gRPC listeners are plaintext and accept only the engine's bootstrap token. They bind the --listen address, 127.0.0.1 by default. To reach them from another machine, put them behind a proxy that terminates TLS and authenticates callers. Binding them to a public address takes --allow-insecure-listen, and on a multitenant server they refuse it. See Listener security and Security.