Relay nodes
Turn a Prisma model into a Relay node with global IDs and efficient node(id) lookups.
The Prisma plugin wires into the Relay plugin so a Prisma model becomes a Relay node with a global ID and an efficient node(id: ID!) lookup. builder.prismaNode takes the place of builder.prismaObject: it defines the same object type and, on top of it, implements the Node interface and the id field for you.
These examples assume the builder is set up with both PrismaPlugin and RelayPlugin and a prisma client in scope (see Setup for the generator, PrismaTypes, and builder wiring).
Defining a node
prismaNode takes the same options as prismaObject plus one required id option that mirrors the id option of the Relay plugin's node method. The simplest form points id.field at a unique column or index, and Pothos derives both the global ID and the lookup from it.
builder.prismaNode('Player', {
// Which database column backs the node's global id.
id: { field: 'id' },
// fields work exactly like builder.prismaObject.
fields: (t) => ({
name: t.exposeString('name'),
number: t.exposeInt('number'),
team: t.relation('team'),
}),
});With id.field set, the node(id:) query loads the record with a prisma.player.findUnique keyed on that column, with no resolver to write.
Customizing the id
To format the global ID yourself, replace id.field with an id.resolve function that returns a string from a node instance. Pair it with findUnique, whose return value is passed as the where of a prisma.player.findUnique to load the node back from that formatted ID. This is for cases where the raw column value isn't the shape you want to expose.
builder.prismaNode('Player', {
id: { resolve: (player) => String(player.id) },
// The return value becomes the `where` of a prisma.player.findUnique.
findUnique: (id) => ({ id: Number.parseInt(id, 10) }),
fields: (t) => ({
name: t.exposeString('name'),
number: t.exposeInt('number'),
team: t.relation('team'),
}),
});Missing records
When node(id:) resolves to a global ID that no longer maps to a row, the default behavior is to throw. Some clients would rather receive null for a deleted or never-existent node than surface an error. Set nullable: true to load with findUnique instead of findUniqueOrThrow and return null on a miss.
builder.prismaNode('Player', {
id: { resolve: (player) => String(player.id) },
nullable: true,
fields: (t) => ({
name: t.exposeString('name'),
number: t.exposeInt('number'),
team: t.relation('team'),
}),
});Every other prismaObject option carries over unchanged, including name and variant for exposing multiple GraphQL types from one model.