Skip to main content

GraphQL SDL generation

The driver's Neo4jSchemaGenerator exports your metadata as GraphQL SDL compatible with @neo4j/graphql. Two things this is unusually good for:

  • Instant APIs — a standard GraphQL schema over your existing models, with @node and @relationship directives already pointing at the right labels and edge types.
  • AI-ready schemas — agents and LLMs do markedly better with an SDL carrying semantic descriptions than with a bare table dump.
const sdl = orm.schema.getGraphSdl();
console.log(sdl);
From SDL to a running API

A complete GraphQL backend with NestJS takes this string the rest of the way: @neo4j/graphql turns it into an executable schema, NestJS serves it, and the resulting CRUD API reads and writes the same nodes your EntityManager does.

Comments become docstrings​

comment is supported on entities and properties in both APIs, and lands as a triple-quoted docstring:

export const ProductSchema = defineEntity({
name: 'Product',
comment: 'An item available for purchase.',
properties: (p) => ({
id: p.uuid().primary(),
price: p.float({ comment: 'Retail price in USD.' }),
}),
});
"""
An item available for purchase.
"""
type Product @node {
id: ID!
"""
Retail price in USD.
"""
price: Float!
}

What lands in the SDL​

ModelSDL
An entitytype X @node — with labels: [...] when it declares extra labels
A relation property@relationship(type: "…", direction: IN | OUT)
A relationship entityproperties: "ActedIn" on the relationship directive
An interface entityinterface X, plus @declareRelationship on relations it declares
A fulltext search field@fulltext(indexes: [...]) on every type the index covers
An auto-generated pivot, or a synthesized inverse sideNothing — plumbing, not model

The search field itself is never a field of the type: it stores nothing, and the directive is where it belongs. queryName comes from the search field's options, and is derived from the type and the scored fields when absent, so two indexes on one entity cannot collide.