
This is a GraphQL-Endpoint extension for Neo4j. It is part of the GRANDstack
Based on your GraphQL schema, it translates GraphQL Queries and Mutations into Cypher statements and executes them on Neo4j.
It offers both an HTTP API, as well as, Neo4j Cypher Procedures to execute and manage your GraphQL API.
Installation
Download and install Neo4j Desktop
Neo4j Desktop provides a quick install button for neo4j-graphql.
After creating your database you can find it under "Manage" in the "Plugins" tab for a single click install.

Use with neo4j-graphql-cli
This extension is utilized, when you use neo4j-graphql-cli
This tool
-
launches a Neo4j Sandbox with your GraphQL schema
-
provides the
/graphql/
endpoint, -
a Neo4j server,
-
an hosted GraphiQL for it.
npm install -g neo4j-graphql-cli neo4j-graphql movies-schema.graphql
Quickstart
To generate some graph data in Neo4j just run :play movie graph
in your Neo4j Browser.
GraphiQL
The best tool to use is GraphiQL the GraphQL UI. Get and install it.
Enter your GraphQL URL, like http://localhost:7474/graphql/
(note the trailing slash).
If your Neo4j Server runs with authentication enabled, add the appropriate Basic-Auth (base64 encoded) username:password
header in the "Edit HTTP Headers" screen.
Authorization
header value.echo "Basic $(echo -n "neo4j:<password>" | base64)"
Uploading a GraphQL Schema
Here is a small example schema for the movie data. Just a Movie with actors, and a Person with movies.
Simple properties are mapped directly while the relationships are mapped to fields movies
and actors
type Movie {
title: String!
released: Int
actors: [Person] @relation(name:"ACTED_IN",direction:IN)
}
type Person {
name: String!
born: Int
movies: [Movie] @relation(name:"ACTED_IN")
}
You can POST a GraphQL schema to the /graphql/idl/
endpoint or run the CALL graphql.idl('schema-text')
procedure.
The payload is parsed and stored in Neo4j and used subsequently as the backing GraphQL schema for validating and executing queries.
CALL graphql.idl('
type Movie {
title: String!
released: Int
actors: [Person] @relation(name:"ACTED_IN",direction:IN)
}
type Person {
name: String!
born: Int
movies: [Movie] @relation(name:"ACTED_IN")
}
')
You should then be able to see your schema in the Docs section of GraphiQL.
This also gives you auto-completion, validation and hints when writing queries.
To visualize your GraphQL schema in Neo4j Browser use: call graphql.schema()
.

Auto-Generated Query Types
From that schema, the plugin automatically generate Query Types for each of the declared types.
e.g. Movie(title,released,first,offset,_id,orderBy, filter): [User]
-
Each field of the entity is available as query argument, with an equality check (plural for list-contains)
-
We also provide a
filter
argument for more complex filtering with nested predicates, also for relation-fields (see graphcool docs) -
For ordered results there is a
orderBy
argument -
And
first
,offset
allow for pagination
Now you can for instance run this query:
{ Person(name:"Kevin Bacon") {
name
born
movies {
title
released
tagline
}
}
}

query Nineties($released: Long, $letter: String)
{ Movie(released: $released,
filter: {title_starts_with: $letter,
actors_some: { name_contains: $letter}}) {
title
released
actors(first: 3) {
name
born
movies(first: 1, orderBy: title_desc) {
title
released
}
}
}
}
# query variables
{ "released":1995, "letter":"A"}
This query declares query name and parameters (first line), which are passed separately ("Query Parameters box") as JSON.
And get this result:

Auto-Generated Mutations
Additionally Mutations for each type are created, which return update statistics.
e.g. for the Movie
type:
-
createMovie(title: ID!, released: Int) : String
-
updateMovie(title: ID!, released: Int) : String
-
deleteMovie(title: ID!) : String
and for it’s relationships:
-
addMovieActors(title: ID!, actors:[ID]!) : String
-
deleteMovieActors(title: ID!, actors:[ID]!) : String
Those mutations then allow you to create and update your data with GraphQL.
mutation {
createPerson(name:"Chadwick Boseman", born: 1977)
}
{ "data": {
"createPerson": "Nodes created: 1\nProperties set: 2\nLabels added: 1\n"
}
}
mutation {
pp: createMovie(title:"Black Panther", released: 2018)
lw: createPerson(name:"Letitia Wright", born: 1993)
cast: addMovieActors(title: "Black Panther",
actors:["Chadwick Boseman","Letitia Wright"])
}
If the same mutations is called multiple times, you need to use alias prefixes to avoid clashes in the returned data, which is keyed on mutation names.

You can use those mutations also to load data from CSV or JSON.
Directives
Directives like @directiveName(param:value)
can be used to augment the schema with additional meta-information that we use for processing.
You have already seen the @relation(name:"ACTED_IN", direction:"IN")
directive to map entity references to graph relationships.
The @cypher
directive is a powerful way of declaring computed fields, query types and mutations with a Cypher statement.
directors
type Movie {
...
directors: [Person] @cypher(statement:"MATCH (this)<-[:DIRECTED]-(d) RETURN d")
}
schema {
query: QueryType
mutation: MutationType
}
type QueryType {
...
coActors(name:ID!): [Person] @cypher(statement:"MATCH (p:Person {name:$name})-[:ACTED_IN]->()<-[:ACTED_IN]-(co) RETURN distinct co")
}
type MutationType {
...
rateMovie(user:ID!, movie:ID!, rating:Int!): Int
@cypher(statement:"MATCH (p:Person {name:$user}),(m:Movie {title:$movie}) MERGE (p)-[r:RATED]->(m) SET r.rating=$rating RETURN r.rating")
}
type Movie {
title: String!
released: Int
actors: [Person] @relation(name:"ACTED_IN",direction:IN)
directors: [Person] @cypher(statement:"MATCH (this)<-[:DIRECTED]-(d) RETURN d")
}
type Person {
name: String!
born: Int
movies: [Movie] @relation(name:"ACTED_IN")
}
schema {
query: QueryType
mutation: MutationType
}
type QueryType {
coActors(name:ID!): [Person] @cypher(statement:"MATCH (p:Person {name:$name})-[:ACTED_IN]->()<-[:ACTED_IN]-(co) RETURN distinct co")
}
type MutationType {
rateMovie(user:ID!, movie:ID!, rating:Int!): Int
@cypher(statement:"MATCH (p:Person {name:$user}),(m:Movie {title:$movie}) MERGE (p)-[r:RATED]->(m) SET r.rating=$rating RETURN r.rating")
}
Procedures
This library also comes with Cypher Procedures to execute GraphQL from within Neo4j.
CALL graphql.query('{ Person(born: 1961) { name, born } }')
WITH 'query ($year:Long,$limit:Int) { Movie(released: $year, first:$limit) { title, actors {name} } }' as query
CALL graphql.query(query,{year:1995,limit:5}) YIELD result
UNWIND result.Movie as movie
RETURN movie.title, [a IN movie.actors | a.name] as actors

CALL graphql.execute('mutation { createMovie(title:"The Shape of Water", released:2018)}')
Other Information
Please leave Feedback and Issues
You can get quick answers on Neo4j-Users Slack in the #neo4j-graphql
channel
License: Apache License v2.
This branch for Neo4j 3.3.x
Features
name | information | example |
---|---|---|
entities |
each node label represented as entity |
|
multi entities |
multiple entities per query turned into |
|
property fields |
via sampling property names and types are determined |
|
field parameters |
all properties can be used as filtering (exact/list) input parameters, will be turned into Cypher parameters |
|
query parameters |
passed through as Cypher parameters |
|
filter arguments |
nested input types for arbitrary filtering on query types and fields |
|
filter arguments for relations |
filtering on relation fields, suffixes ("",not,some, none, single, every) |
|
relationships |
via a |
|
ordering |
via an extra |
|
pagination |
via |
|
schema first IDL support |
define schema via IDL |
|
Mutations |
create/delete mutations inferred from the schema |
|
Cypher queries |
|
|
Cypher updates |
Custom mutations by executing |
|
extensions |
extra information returned |
|
Note
|
@cypher directives can have a passThrough:true argument, that gives sole responsibility for the nested query result for this field to your Cypher query.
You will have to provide all data/structure required by client queries.
Otherwise, we assume if you return object-types that you will return the appropriate nodes from your statement.
|
Advanced Usage
The extension works with Neo4j 3.1 and 3.2, the code on this branch is for 3.3.
Please consult the Neo4j documentation for file locations for the other editions on the different operating systems.
Manual Installation
-
Download the appropriate neo4j-graphql release for your version.
-
Copy the jar-file into Neo4j’s
plugins
directory -
Edit the Neo4j settings (
$NEO4J_HOME/conf/neo4j.conf
) to add:
dbms.unmanaged_extension_classes=org.neo4j.graphql=/graphql
-
You might need to add
,graphql.*
if your config contains this line:
dbms.security.procedures.whitelist=
-
(Re)start your Neo4j server
Note
|
Neo4j Desktop: the configuration is available under Manage → Settings, the plugins folder via Open Folder.
|
Building manually
git clone https://github.com/neo4j-graphql/neo4j-graphql cd neo4j-graphql git checkout 3.2 mvn clean package cp target/neo4j-graphql-*.jar $NEO4J_HOME/plugins echo 'dbms.unmanaged_extension_classes=org.neo4j.graphql=/graphql' >> $NEO4J_HOME/conf/neo4j.conf $NEO4J_HOME/bin/neo4j restart
Note
|
You might need to add ,graphql.* if your config contains this line: dbms.security.procedures.whitelist=
|
Schema from Graph
If you didn’t provide a GraphQL schema, we try to derive one from the existing graph data.
From sampling the data we add a type
for each Node-Label with all the properties and their types found as fields.
Each relationship-type adds a reference field to the node type, named aType
for A_TYPE
.
Procedures
You can even visualize remote graphql schemas, e.g. here from the GitHub GraphQL API. Make sure to generate the Personal Access Token to use in your account settings.
call graphql.introspect("https://api.github.com/graphql",{Authorization:"bearer d8xxxxxxxxxxxxxxxxxxxxxxx"})
Resources
Neo4j-GraphQL
-
neo4j-graphql Tools and Libraries related to Neo4j’s GraphQL support
-
GraphQL page on neo4j.com
-
GraphQL inspired Cypher features Map projections and Pattern comprehensions
Libraries & Tools
-
GraphQL-Java which we use in this project
Neo4j Admin API
The project also contains an experimental endpoint to expose procedures deployed into Neo4j (built-in and external) as a GraphQL admin API endpoint.
If you access /graphql/admin
in GraphiQL or GraphQL Playground, you should see those separated into queries and mutations in the schema.
You have to explicitely allow procedures to be exposed, via the config setting graphql.admin.procedures.(read/write)
with either Neo4j procedure syntax or admin-endpoint field names.
By setting it to:
graphql.admin.procedures.read=db.*,dbms.components,dbms.queryJ* graphql.admin.procedures.write=db.create*,dbIndexExplicitFor*
For documentation on each please check the provided description or the documentation of the original procedure in the Neo4j or other manuals.

You will have to provide the appropriate user credentials as HTTP Basic-Auth headers, the procedures are executed under the priviledges of that user.
You can read more about it in this article^.