Skip to content
gr

Running the server

gr serve, driver connectivity (Go/Python/JS/Java), auth, HTTP API, TLS, and metrics.

Starting the server

gr serve graph.gr

By default, gr listens on:

  • Bolt: 0.0.0.0:7687 (the Neo4j Bolt wire protocol)
  • HTTP: 0.0.0.0:7474 (the Neo4j HTTP API)

Override the addresses:

gr serve graph.gr --bolt-addr 127.0.0.1:7687 --http-addr 127.0.0.1:7474

The server uses the same .gr file the library opens. There is no import step; changes made through the Bolt server are immediately visible to library users in the same process (if any) and vice versa.

Connecting with drivers

Go (neo4j-go-driver)

import "github.com/neo4j/neo4j-go-driver/v5/neo4j"

driver, err := neo4j.NewDriverWithContext("bolt://localhost:7687", neo4j.NoAuth())
if err != nil {
    log.Fatal(err)
}
defer driver.Close(ctx)

session := driver.NewSession(ctx, neo4j.SessionConfig{})
defer session.Close(ctx)

result, err := session.Run(ctx,
    "MATCH (p:Person {name:$name}) RETURN p.age AS age",
    map[string]any{"name": "Alice"},
)
if err != nil {
    log.Fatal(err)
}
for result.Next(ctx) {
    fmt.Println(result.Record().AsMap())
}

Python (neo4j)

from neo4j import GraphDatabase

driver = GraphDatabase.driver("bolt://localhost:7687", auth=None)
with driver.session() as session:
    result = session.run("MATCH (p:Person {name:$name}) RETURN p.age", name="Alice")
    for record in result:
        print(record["p.age"])
driver.close()

JavaScript (neo4j-driver)

import neo4j from 'neo4j-driver'

const driver = neo4j.driver('bolt://localhost:7687', neo4j.auth.none())
const session = driver.session()

const result = await session.run(
  'MATCH (p:Person {name:$name}) RETURN p.age AS age',
  { name: 'Alice' }
)
for (const record of result.records) {
  console.log(record.get('age').toNumber())
}
await session.close()
await driver.close()

Java

import org.neo4j.driver.*;

try (Driver driver = GraphDatabase.driver("bolt://localhost:7687", AuthTokens.none());
     Session session = driver.session()) {
    Result result = session.run(
        "MATCH (p:Person {name:$name}) RETURN p.age AS age",
        Values.parameters("name", "Alice")
    );
    while (result.hasNext()) {
        System.out.println(result.next().get("age").asInt());
    }
}

Authentication

By default, gr serve requires no authentication (suitable for local development). To require a password:

gr create-user admin --password s3cr3t --role admin
gr serve graph.gr

Then connect with basic auth:

# Go driver:
neo4j.BasicAuth("admin", "s3cr3t", "")
# Python:
GraphDatabase.driver("bolt://localhost:7687", auth=("admin", "s3cr3t"))

Roles: reader, editor, publisher, admin. See gr --help for create-user, grant-role, revoke-role, and drop-user.

The HTTP JSON API

gr exposes a subset of the Neo4j HTTP Transactional API on the HTTP port.

Start a transaction:

POST /db/gr/tx
Content-Type: application/json

{"statements": [{"statement": "MATCH (n:Person) RETURN n.name"}]}

Run more statements in the same transaction:

POST /db/gr/tx/{id}
{"statements": [...]}

Commit:

POST /db/gr/tx/{id}/commit

Rollback:

DELETE /db/gr/tx/{id}

Health check:

GET /health

Returns 200 OK with {"status":"ok"} when the server is ready.

TLS

Provide a certificate and key:

gr serve graph.gr --tls-cert server.crt --tls-key server.key

Drivers use bolt+s://localhost:7687 for single-hop TLS or bolt+ssc://localhost:7687 for self-signed certificates.

Observability

Prometheus metrics on a separate port:

gr serve graph.gr --metrics-addr 0.0.0.0:9090

Metrics include: active connections, queries per second, query latency percentiles, transaction rate, buffer pool hit rate, WAL write rate.

Slow query log:

gr serve graph.gr --query-log /var/log/gr-queries.log --slow-query-threshold 100ms

Queries that take longer than the threshold are appended to the log as JSON lines.