neo4j-graphql-skill
Build and configure a GraphQL API backed by Neo4j using @neo4j/graphql v7 (current) or v5 (LTS). Covers Neo4jGraphQL constructor, getSchema(), assertIndexesAndConstraints(), type definitions with @node, @relationship (IN/OUT/UNDIRECTED), @cypher for custom resolvers, @authorization/@authentication f
By neo4j-contrib · 527 installs
npx skills add neo4j-contrib/neo4j-skills --skill neo4j-graphql-skill
Source repository · Upstream listing
When to Use
Creating a GraphQL API from a Neo4j graph schema with @neo4j/graphql
Writing type definitions with @relationship , @cypher , @authorization directives
Using OGM for server side programmatic Neo4j access (bypasses GraphQL auth)
Configuring auto generated queries, mutations, subscriptions
Securing types/fields with JWT or JWKS based @authorization rules
Migrating from v5/v6 to v7 (breaking changes below)
When NOT to Use
Raw Cypher queries outside GraphQL resolvers → neo4j cypher skill
Spring Data Neo4j / Java entity mapping → neo4j spring data skill
Generic GraphQL without Neo4j — outside scope
Version Matrix
Version Status Notes
v7 Current — use ≥ 7.6.0 @node required; options removed; explicit eq syntax
v5 LTS — use ≥ 5.12.15 Older syntax; options: {limit, offset, sort} still valid
Default to v7 unless codebase is on v5.
Security patches — upgrade before shipping auth:
Fix Fixed in
Subscriptions accepted an unverified JWT from WebSocket connectionParams (auth/authz bypass) 7.5.6 / 5.12.14
Field level @authentication on a root custom resolver field ignored when the operation type also had type level @authentication (privilege escalation) 7.6.0 / 5.12.15
Step 1 — Install
For subscriptions (CDC required):
Step 2 — Minimal Server Setup
Key Directives
@node (v7 required)
@relationship — Full Syntax
Querying Relationship Properties — Connection API
For each relationship with properties: , a {field}Connection field is auto generated. Access rel properties via actorsConnection.edges.properties , not via actors :
@cypher — Custom Resolver
this refers to the current node in field level @cypher. Parameters are passed as $paramName .
@cypher — Field Arguments and extend type
@id and @timestamp
@alias — Map GraphQL field to Neo4j property
@fulltext and @vector
Index must exist in Cypher before use. Phrase capable @vector indexes accept maxPhraseLength [7.6.0] to cap embedding cost. Full syntax, generated query shapes, provider config: [references/search directives.md](references/search directives.md).
Security — @authentication and @authorization
Step 1: Configure JWT in constructor
Step 2: Pass token in context
Step 3: Apply @authentication and @authorization
BEFORE vs AFTER : CREATE supports only AFTER ; READ supports only BEFORE .
Auto Generated Operations
Operation Generated Name Example
Query all {plural} movies(where, sort, limit, offset)
Cursor pagination {plural}Connection moviesConnection(first, after, where, sort)
Create create{Plural} createMovies(input: [MovieCreateInput!]!)
Update update{Plural} updateMovies(where, update)
Delete delete{Plural} deleteMovies(where, delete)
v7 Filter Syntax (explicit eq )
Nested Mutations
OGM — Programmatic Access
OGM bypasses GraphQL authorization — use only in trusted server side contexts.
Install separately: npm install @neo4j/graphql ogm
Subscriptions (CDC Required)
Requires Neo4j CDC enabled in FULL mode. See [CDC docs](https://neo4j.com/docs/cdc/current/).
Authenticate subscriptions with a verified token in the WebSocket context; a pre decoded jwt is trusted only when set server side (7.5.6 / 5.12.14 stopped trusting client supplied connectionParams JWTs).
Schema Control Directives
Common Errors
Error Cause Fix
Type 'X' not found Missing @node on type (v7) Add @node to every node type
@cypher field returns null columnName mismatch with RETURN alias Match columnName exactly to RETURN alias
Relationship direction mismatch Both sides declare same direction Inverse: if A has direction: OUT , B must have direction: IN
assertIndexesAndConstraints throws @id constraint not in DB Add { options: { create: true } } or run CREATE CONSTRAINT manually
Auth not applied JWT not in context Pass token: req.headers.authorization in context function
0 results with valid data v7 filter missing eq Use { field: { eq: value } } not { field: value }
connectOrCreate not found Removed in v7 Use connect + create separately
Memory errors on large mutations Complex Cypher generation Batch mutations; increase server.memory.heap.max size
@subscription not generating v7 requires explicit enable Add features: { subscriptions: true } to constructor
v6 → v7 Breaking Changes Summary
v6 v7
@node optional @node required on every node type
options: { limit, sort } limit , sort as direct args
{ field: value } filter { field: { eq: value } }
connectOrCreate nested mutation Removed — use connect + create
directed arg on queries queryDirection in @relationship
Single rel fields actor: Person Must use list actors: [Person!]!
@private directive Removed
@unique directive Removed
References
[Neo4j GraphQL Docs](https://neo4j.com/docs/graphql/current/) — full directive reference, migration guides
[GraphAcademy: GraphQL Basics](https://graphacademy.neo4j.com/courses/graphql basics/) — hands on course
[GitHub: @neo4j/graphql](https://github.com/neo4j/graphql) — changelog, issues
[CDC Setup](https://neo4j.com/docs/cdc/current/) — required for subscriptions
[references/search directives.md](references/search directives.md) — @fulltext , @vector , maxPhraseLength
Checklist
[ ] @node on every GraphQL type representing a Neo4j node (v7 hard requirement)
[ ] @id on identity fields (triggers CREATE CONSTRAINT via assertIndexesAndConstraints )
[ ] assertIndexesAndConstraints called on startup with try/catch
[ ] @relationship direction correct: OUT = arrow leaves this node, IN = arrow enters
[ ] Both sides of relationship declared with inverse directions
[ ] @cypher columnName matches RETURN alias exactly
[ ] JWT secret or JWKS URL in features.authorization.key ; token passed in context
[ ] @authorization filter vs validate chosen deliberately (silent hide vs thrown error)
[ ] v7: filters use explicit { field: { eq: value } } syntax
[ ] v7: limit / sort passed as direct query args (not options wrapper)
[ ] OGM: await ogm.init() called before any ogm.model() usage
[ ] Subscriptions: CDC enabled in FULL mode before enabling features.subscriptions
[ ] @neo4j/graphql ≥ 7.6.0 (v7) or ≥ 5.12.15 (LTS) — earlier versions have auth bypasses
[ ] .env holds credentials; .env in .gitignore