Query the database

To run a query on a database, submit a POST request to the following endpoint:

http://<host>:<port>/db/<databaseName>/tx/commit
  • <host> is where the Neo4j instance is located (example localhost, xxx.databases.neo4j.io),

  • <port> is the port on which the Neo4j HTTP server is set to listen on (default 7474),

  • <databaseName> is the database you want to query (example neo4j).

The server wraps the submitted Cypher query in a (implicit) transaction for you. This means that in case any part of the query fails, the database will be reverted back to its status before any part of the query was executed. To control the lifecycle of transactions, see Run transactions.

Each request must include an Authorization header, see Authentication and authorization for more information.

Example request

POST http://localhost:7474/db/neo4j/tx/commit
Accept: application/json;charset=UTF-8
Content-Type: application/json
Authorization: Basic bmVvNGo6dmVyeXNlY3JldA==
{
  "statements": [
    {
      "statement": "MERGE (n:Person {name: $name, age: $age}) RETURN n",
      "parameters": {
        "name": "Alice",
        "age": 42
      }
    }
  ]
}

Example response

200: OK
Content-Type: application/json;charset=utf-8
{
  "results": [ {
    "columns": ["n"],
    "data": [ {
      "row": [ {
        "name": "Alice",
        "age": 42
      } ],
      "meta": [ {
        "id": 36,
        "elementId": "4:0ea4a108-32c5-498c-99e7-95cc67ab5f7d:36",
        "type": "node",
        "deleted": false
      } ]
    } ]
  } ],
  "errors": [],
  "lastBookmarks": [
    "FB:kcwQDqShCDLFSYyZ55XMZ6tffRuQ"
  ]
}

Literal line breaks are not allowed inside Cypher statements submitted through the API (as per JSON specifications). This means that queries should fit on a single line. You can replace line breaks with spaces, as Cypher parses them equivalently.

Execute multiple queries

You can send multiple Cypher statements in the same request. The server runs them in sequence, but separate from each other, so a statement cannot reference a variable defined in another statement. The response contains the result of each statement, in order.

Example request

POST http://localhost:7474/db/neo4j/tx/commit
Accept: application/json;charset=UTF-8
Content-Type: application/json
Authorization: Basic bmVvNGo6dmVyeXNlY3JldA==
{
  "statements": [
    { "statement": "RETURN 1" },
    { "statement": "RETURN 2" }
  ]
}

Example response

200: OK
Content-Type: application/json;charset=utf-8
{
  "results": [
    {
      "columns": ["1"],
      "data": [{ "row": [1], "meta": [null] }]
    },
    {
      "columns": ["2"],
      "data": [{ "row": [2], "meta": [null] }]
    }
  ],
  "errors": [],
  "lastBookmarks": [
    "FB:kcwQDqShCDLFSYyZ55XMZ6tffRuQ"
  ]
}

If one of the queries fails, all statements submitted with the request will be rolled back. In the example below, the second statement fails due to a division by 0. The result is that not only no :Number nodes are created (not even the one with val: 1), but no :Person nodes are created either.

Example request

POST http://localhost:7474/db/neo4j/tx/commit
Accept: application/json;charset=UTF-8
Content-Type: application/json
Authorization: Basic bmVvNGo6dmVyeXNlY3JldA==
{
  "statements": [
    {
      "statement": "MERGE (p:Person {name: $name}) RETURN p",
      "parameters": {
        "name": "Bob"
      }
    },
    {
      "statement": "UNWIND [1, 0] AS i MERGE (n:Number {val: 1/i}) RETURN n"
    },
  ]
}

Example response

200: OK
Content-Type: application/json;charset=utf-8
{
  "results": [ {
    "columns": [ "p" ],
    "data": [ {
      "row": [ {
        "name": "Bob"
      } ],
      "meta": [ {
        "id": 8,
        "elementId": "4:0ea4a108-32c5-498c-99e7-95cc67ab5f7d:8",
        "type": "node",
        "deleted": false
      } ]
    ] }
  ] },
  {
    "columns": [ "n" ],
    "data": [ {
      "row": [ {
        "val": 1
      } ],
      "meta": [ {
        "id": 1,
        "elementId": "4:0ea4a108-32c5-498c-99e7-95cc67ab5f7d:1",
        "type": "node",
        "deleted": false
      } ]
    } ]
  } ],
  "errors": [ {
    "code": "Neo.ClientError.Statement.ArithmeticError",
    "message": "/ by zero"
  } ]
}

Queries with CALL {} IN TRANSACTIONS

Take extra care with queries using the Cypher clause CALL {} IN TRANSACTIONS. Because those queries spawn further transactions of their own, there can be unexpected behaviors due to their interaction with the surrounding transaction.

Rollback behaviour

While a failure in any statement will cause all statements in the request to be rolled back, that does not apply to the ones using CALL {} IN TRANSACTIONS. Since the transactions created by that clause get independently committed, the server cannot roll them back in case the other parts fail.

In the example below, even if the second statement fails execution due to the division by zero, the first statement is not reverted. The result is two new :Person nodes.

POST http://localhost:7474/db/neo4j/tx/commit
Accept: application/json;charset=UTF-8
Content-Type: application/json
Authorization: Basic bmVvNGo6dmVyeXNlY3JldA==
{
  "statements": [
    {
      "statement": "UNWIND ['Sofia', 'Greg'] AS name CALL { WITH name CREATE (:Person {name: name}) } IN TRANSACTIONS OF 1 ROWS RETURN name"
    },
    {
      "statement": "UNWIND [1, 0] AS i MERGE (n:Number {val: 1/i}) RETURN n"
    },
  ]
}

Query order

Queries containing CALL {} In TRANSACTIONS must come first in the order of the statements JSON list. Failure to do so will result in an error.

Example request

POST http://localhost:7474/db/neo4j/tx/commit
Accept: application/json;charset=UTF-8
Content-Type: application/json
Authorization: Basic bmVvNGo6dmVyeXNlY3JldA==
{
  "statements": [
    {
      "statement": "MERGE (p:Person {name: $name}) RETURN p.name",
      "parameters": {
        "name": "Bob"
      }
    },
    {
      "statement": "UNWIND [1, 0] AS i CALL { WITH i MERGE (:Number {val: 1/i}) } IN TRANSACTIONS OF 1 ROWS RETURN i"
    },
  ]
}

Example response

200: OK
Content-Type: application/json;charset=utf-8
{
  "results": [ {
    "columns": [ "p.name" ],
    "data": [ {
      "row": [ "Bob" ],
      "meta": [ null ]
    }]
  },
  {
    "columns": [ "i" ],
    "data": []
  } ],
  "errors": [ {
    "code": "Neo.DatabaseError.Statement.ExecutionFailed",
    "message": "Expected transaction state to be empty when calling transactional subquery. (Transactions committed: 0)"
  } ]
}

Query parameters

In order to speed up queries in repeated scenarios, avoid using literals and replace them with parameters wherever possible. This allows the server to cache query plans and can result in a significant performance improvement.

Do — Use query parameters
{
  "statements": [
    {
      "statement": "MERGE (n:Person {name: $name, age: $age}) RETURN n",
      "parameters": {
        "name": "Alice",
        "age": 42
      }
    }
  ]
}
Do not — Embed literals in query
{
  "statements": [
    {
      "statement": "MERGE (n:Person {name: 'Alice', age: 42}) RETURN n",
    }
  ]
}

See Cypher Manual → Parameters for more information.

Glossary

Cypher

Cypher is Neo4j’s graph query language that lets you retrieve data from the database. It is like SQL, but for graphs.

ACID

Atomicity, Consistency, Isolation, Durability (ACID) are properties guaranteeing that database transactions are processed reliably. An ACID-compliant DBMS ensures that the data in the database remains accurate and consistent despite failures.

causal consistency

A database is causally consistent if read and write queries are seen by every member of the cluster in the same order. This is stronger than eventual consistency.

transaction

A transaction is a unit of work that is either committed in its entirety or rolled back on failure. An example is a bank transfer: it involves multiple steps, but they must all succeed or be reverted, to avoid money being subtracted from one account but not added to the other.