unlight/prisma-nestjs-graphql
Generate object types, inputs, args, etc. from prisma schema file for usage with @nestjs/graphql module
Generate object types, inputs, args, etc. from prisma schema file for usage with @nestjs/graphql module.
npm install --save-dev prisma-nestjs-graphql @prisma/generator-helper identity-type
schema.prisma filegenerator nestgraphql {
provider = "prisma-nestjs-graphql"
// Or explicit node execution
provider = "node node_modules/prisma-nestjs-graphql/bin.mjs"
output = "../src/@generated"
}
Create prisma/nestgraphql.config.mjs and reference it in your schema:
generator nestgraphql {
provider = "prisma-nestjs-graphql"
configFile = "./nestgraphql.config.mjs"
}
// prisma/nestgraphql.config.mjs
/**
* @type {import('prisma-nestjs-graphql').ExternalConfig}
*/
export default {
output: '../src/@generated',
};
All generator options—including decorators, fields, useInputType, customImport,
and graphqlScalars—are defined as structured JavaScript objects in the config file
instead of using underscore-delimited keys (decorate_1_*, fields_Validator_*, etc.)
directly in the schema.
npx prisma generate
Decimal and Json types, you need install:npm install graphql-type-json prisma-graphql-type-decimal
Or write you own graphql scalar types, read more on docs.nestjs.com.
No download data available
Used by 1 tracked package
Instead of defining all options as flat keys in schema.prisma, you can use a structured JavaScript config file
for better readability, validation, and IDE autocompletion.
Before (underscore-delimited keys in schema.prisma):
fields_Validator_from = "class-validator"
fields_Validator_input = true
decorate_1_type = "CreateOneUserArgs"
decorate_1_field = data
decorate_1_from = "class-validator"
decorate_1_name = ValidateNested
decorate_1_arguments = "[]"
After (structured objects in nestgraphql.config.mjs):
fields: {
Validator: { from: 'class-validator', input: true },
},
decorators: [
{
match: ({ objectName, propertyName }) =>
objectName === 'CreateOneUserArgs' && propertyName === 'data',
from: 'class-validator',
name: 'ValidateNested',
arguments: [],
namedImport: true,
},
],
The old flatten-style keys still work if no configFile is specified.
Options from the config file take precedence.
outputOutput folder, if path relative and defined in schema it will be relative to schema,
if defined in config file it will be relative to this config file.
Type: string
outputFilePatternFile path and name pattern
Type: string
Default: {model}/{name}.{type}.ts
Possible tokens:
{model} Model name in dashed case or 'prisma' if unknown{name} Dashed-case name of model/input/arg without suffix{type} Short type name (model, input, args, output){plural.type} Plural short type name (models, inputs, enums)tsConfigFilePathPath to tsconfig.json (absolute path or relative to current working directory)
Type: string | undefined
Default: tsconfig.json if exists, undefined otherwise
prismaClientImportThe path to use to import the Prisma Client package
Type: string | undefined
Default: @prisma/client
importExtensionAppend an extension to relative import and export module specifiers (without dot, eg. 'js, 'ts', 'mjs')
Type: string
Default: '' (empty string)
combineScalarFiltersCombine nested/nullable scalar filters to single
Type: boolean
Default: true
noAtomicOperationsRemove input types for atomic operations
Type: boolean
Default: true
reExportCreate index.ts file with re-export
Type: enum
Values:
None Default, create nothing
Directories Create index file in all root directories
Single Create single index file in output directory
All Create index file in all root directories and in output directory
Example configuration:
generator nestgraphql {
provider = "node node_modules/prisma-nestjs-graphql"
output = "../src/@generated"
reExport = Directories
}
emitSingleGenerate single file with merged classes and enums.
Type: boolean
Default: false
emitCompiledEmit compiled JavaScript and definitions instead of TypeScript sources.
Type: boolean
Default: false
emitBlocksEmit only selected blocks. Be aware, that some blocks do depend on others, e.g. one can't emit models without emitting enums.
Type: ("args" | "inputs" | "outputs" | "models" | "enums")[]
Default: ["args", "inputs", "outputs", "models", "enums"]
omitModelsCountOmit _count field from models.
Type: boolean
Default: false
purgeOutputDelete all files in output folder.
Type: boolean
Default: false
noTypeIdDisable usage of graphql ID type and use Int/Float for fields marked as @id in schema.
Type: boolean
Default: false
typeListNullableAdds nullable: true for relation list properties out output models,
it makes graphql field looks like [Type!], default [Type!]!
Type: boolean
Default: false
requireSingleFieldsInWhereUniqueInputWhen a model *WhereUniqueInput class has only a single field, mark that field as required (TypeScript) and not nullable (GraphQL).
See #58 for more details.
Type: boolean
Default: false
Note: It will break compatiblity between Prisma types and generated classes.
unsafeCompatibleWhereUniqueInputSet TypeScript property type as non optional for all fields in *WhereUniqueInput classes.
See #177 for more details.
Type: boolean
Default: false
inputTypeSince GraphQL does not support input union type, this setting map allow to choose which input type is preferable.
New (config file):
/**
* Input type mapping.
* Select which input type should be exposed when multiple candidates exist.
* Since GraphQL does not support input unions, this setting can resolve
* ambiguous fields (e.g. `UserRelationFilter` vs `UserWhereInput`).
*
* Supports two variants:
* - object map: `{ [inputTypeName]: { [fieldName|'*']: pattern } }`
* - function: return either an `InputTypeRef` or a string pattern
* (same matching behavior as map patterns, including `match:` syntax)
* @example
* // Force all WhereInput relation properties to use the plain WhereInput type:
* { WhereInput: { '*': 'WhereInput' } }
* // Or for a specific property in a specific type:
* { PostCreateInput: { author: 'UserCreateNestedOneWithoutPostsInput' } }
* // Function variant returning a pattern:
* ({ inputTypeName, fieldName }) =>
* inputTypeName.includes('CreateOne') && fieldName === 'data'
* ? 'UncheckedCreate'
* : undefined
*/
inputType: GetInputTypeFunction | ConfigInputTypeMap;
Where:
typeName — Full or partial name of the class where need to choose input typeproperty — Property of the class. Special case ALL means any/all propertiespattern — Part of name (or full) of type to choose; use match:*UncheckedCreateInput for wildcard/negation matchingLegacy (schema.prisma, flatten-style):
generator nestgraphql {
useInputType_{typeName}_{property} = "{pattern}"
}
Example:
export type PostWhereInput = {
author?: XOR<UserRelationFilter, UserWhereInput>;
};
export type UserRelationFilter = {
is?: UserWhereInput;
isNot?: UserWhereInput;
};
export type UserWhereInput = {
AND?: Enumerable<UserWhereInput>;
OR?: Enumerable<UserWhereInput>;
NOT?: Enumerable<UserWhereInput>;
id?: StringFilter | string;
name?: StringFilter | string;
};
We have generated types above, by default property author will be decorated as UserRelationFilter,
to set UserWhereInput need to configure generator the following way (legacy way):
generator nestgraphql {
provider = "node node_modules/prisma-nestjs-graphql"
output = "../src/@generated"
useInputType_WhereInput_ALL = "WhereInput"
}
@InputType()
export class PostWhereInput {
@Field(() => UserWhereInput, { nullable: true })
author?: UserWhereInput;
}
decoratorsModern way to attach custom decorators in config file (decorators: DecoratorItem[]).
decorators: [
{
match: ({ objectName, propertyName }) =>
objectName === 'CreateOneUserArgs' && propertyName === 'data',
from: 'class-validator',
name: 'ValidateNested',
arguments: [],
namedImport: true,
},
{
match: ({ objectName, propertyName }) =>
objectName === 'CreateOneUserArgs' && propertyName === 'data',
from: 'class-transformer',
name: 'Type',
arguments: ['() => {propertyType.0}'],
namedImport: true,
},
];
match receives one argument FieldInfo:
type FieldInfo = {
/**
* Prisma DMMF field location type
* Can be: 'scalar', 'inputObjectTypes', 'outputObjectTypes', 'enumTypes', 'fieldRefTypes'
*/
location: FieldLocation;
/**
* Class name
*/
objectName: string;
/**
* Property name
*/
propertyName: string;
/**
* Property type (may contain TypeScript elements, like parameters for generics, etc.)
*/
propertyType: string;
/**
* GraphQL/Prisma type name
*/
typeName: string;
};
Decorator item type:
type DecoratorItem = {
/** Return `true` to apply this decorator to the current field. */
match: (args: FieldInfo) => boolean;
/** Arguments passed to the decorator call.
* Supports templates like `{propertyType.0}`. */
arguments?: string[];
/** Module specifier to import from (e.g. 'class-validator') */
from: string;
/** Decorator name. Can include namespace, e.g. `Transform.Type`. */
name: string;
/** Import as a named export. */
namedImport: boolean;
/** Import as default export.
* Use `true` to import by decorator name. */
defaultImport?: string | true;
/** Import entire module under this namespace. */
namespaceImport?: string;
};
Special token in arguments: {propertyType.0} resolves to the field's TypeScript type.
Example result:
import { ValidateNested } from 'class-validator';
import { Type } from 'class-transformer';
@ArgsType()
export class CreateOneUserArgs {
@Field(() => UserCreateInput, { nullable: false })
@ValidateNested()
@Type(() => UserCreateInput)
data!: UserCreateInput;
}
Legacy (decorate / decorate_*)
Legacy flatten-style keys in schema.prisma are still supported for backward compatibility:
generator nestgraphql {
decorate_{key}_type = "outmatch pattern"
decorate_{key}_field = "outmatch pattern"
decorate_{key}_from = "module specifier"
decorate_{key}_name = "import name"
decorate_{key}_arguments = "[argument1, argument2]"
decorate_{key}_defaultImport = "default import name" | true
decorate_{key}_namespaceImport = "namespace import name"
decorate_{key}_namedImport = "import name" | true
}
Prefer decorators in nestgraphql.config.* for new configuration.
graphqlScalarsAllow to set custom graphql type for Prisma scalar type.
New (config file):
graphqlScalars: {
BigInt: { name: 'GraphQLBigInt', specifier: 'graphql-scalars' },
}
Legacy (schema.prisma, flatten-style):
graphqlScalars_{type}_name = "string"
graphqlScalars_{type}_specifier = "string"
where {type} is a prisma scalar type name (e.g. BigInt)
Example:
graphqlScalars_BigInt_name = "GraphQLBigInt"
graphqlScalars_BigInt_specifier = "graphql-scalars"
May generate:
import { GraphQLBigInt } from 'graphql-scalars';
export class BigIntFilter {
@Field(() => GraphQLBigInt, { nullable: true })
equals?: bigint | number;
}
It will affect all inputs and outputs types (including models).
customImportsAllow to declare custom import statements.
Note: Only works with emitSingle = true
New (config file):
customImports: [
{ from: 'nestjs-i18n', name: 'I18n', defaultImport: true },
{ from: 'class-transformer', name: 'Transform', namedImport: true },
];
Legacy (schema.prisma, flatten-style):
generator nestgraphql {
customImport_{key}_from = "module specifier"
customImport_{key}_name = "import name"
customImport_{key}_defaultImport = "default import name" | true
customImport_{key}_namespaceImport = "namespace import name"
customImport_{key}_namedImport = "import name" | true
}
Where {key} any identifier to group values (written in flatten style)
customImport_{key}_from - module specifier to import from (e.g nestjs-i18n)customImport_{key}_name - import name or name with namespacecustomImport_{key}_defaultImport - import as defaultcustomImport_{key}_namespaceImport - use this name as import namespacecustomImport_{key}_namedImport - named import (without namespace)fieldDecoratorArgumentsOverride @Field() decorator arguments for specific fields. Use this to customize pagination fields (take, skip, cursor) or other generated Args fields that don't come from your Prisma schema.
Each rule is evaluated against generated field metadata and applied when the match function returns true. Multiple matching rules are merged in order.
New (config file):
fieldDecoratorArguments: [
{
match: ({ objectName, propertyName }) =>
objectName.endsWith('Args') && propertyName === 'take',
decoratorArguments: {
name: 'first',
defaultValue: 10,
description: 'Number of records to return',
},
},
{
match: ({ objectName, propertyName }) =>
objectName.endsWith('Args') && propertyName === 'skip',
decoratorArguments: {
name: 'offset',
defaultValue: 0,
description: 'Number of records to skip',
},
},
]
Available decoratorArguments options:
nullable — Mark field as nullable in GraphQL schemadefaultValue — Default value for the fielddescription — Description shown in GraphQL schemadeprecationReason — Mark field as deprecatedname — Custom name for the field in GraphQL schema (TypeScript property name stays the same)complexity — Complexity value for query cost analysismiddleware — Middleware function name(s) to apply to the fieldMiddleware Example:
To use field middleware, combine customImports with fieldDecoratorArguments. Middleware values are emitted as identifier references (not string literals), allowing them to reference your imported middleware functions:
export default {
customImports: [
{ from: './middleware/logger', name: 'loggerMiddleware', defaultImport: true },
{ from: './middleware/auth', name: 'authMiddleware', defaultImport: true },
],
fieldDecoratorArguments: [
{
match: ({ objectName, propertyName }) =>
objectName === 'User' && propertyName === 'email',
decoratorArguments: {
middleware: ['loggerMiddleware', 'authMiddleware'],
description: 'User email with logging and auth',
},
},
],
};
This generates:
@Field(() => String, {
description: 'User email with logging and auth',
middleware: [loggerMiddleware, authMiddleware]
})
email: string;
Note: When using the name option to override a field name in GraphQL, ensure you understand Prisma field mapping. For example, if you override the take field name to first, you must update any Prisma query logic that references the field by its original name. Consider using a mapping helper if doing this across multiple queries.
The match function receives FieldInfo with:
objectName — Class name (e.g., 'FindManyUserArgs')propertyName — Property name (e.g., 'take', 'skip')propertyType — TypeScript property typetypeName — GraphQL/Prisma type namelocation — Prisma field location ('scalar', 'inputObjectTypes', etc.)Comments with triple slash will projected to typescript code comments
and some @Field() decorator options
For example:
model Product {
/// Old description
/// @deprecated Use new name instead
/// @complexity 1
oldName String
}
May produce:
@ObjectType()
export class Product {
/**
* Old description
* @deprecated Use new name instead
*/
@Field(() => String, {
description: 'Old description',
deprecationReason: 'Use new name instead',
complexity: 1,
})
oldName: string;
}
Special directives in triple slash comments for more precise code generation.
Removes field from GraphQL schema.
By default (without arguments) field will be decorated for hide only in output types (type in schema).
To hide field in input types add input: true.
To hide field in specific type you can use glob pattern match: string | string[]
see outmatch for details.
For config-file based rules, use shouldHideField:
export default {
shouldHideField: ({ location, objectName, propertyName }) =>
location === 'inputObjectTypes' &&
objectName.endsWith('CreateInput') &&
['id', 'createdAt', 'updatedAt'].includes(propertyName),
};
The callback receives FieldInfo (location, objectName, propertyName, propertyType, typeName).
When shouldHideField is defined, it overrides @HideField(...) settings from field comments and legacy decorate rules.
Examples:
@HideField() same as @HideField({ output: true })@HideField({ input: true, output: true })@HideField({ match: 'UserCreate*Input' })model User {
id String @id @default(cuid())
/// @HideField()
password String
/// @HideField({ output: true, input: true })
secret String
/// @HideField({ match: '@(User|Comment)Create*Input' })
createdAt DateTime @default(now())
}
May generate classes:
@ObjectType()
export class User {
@HideField()
password: string;
@HideField()
secret: string;
@Field(() => Date, { nullable: false })
createdAt: Date;
}
@InputType()
export class UserCreateInput {
@Field()
password: string;
@HideField()
secret: string;
@HideField()
createdAt: Date;
}
Applying custom decorators requires configuration of generator.
// Legacy configuration, prefer config file
generator nestgraphql {
fields_{namespace}_from = "module specifier"
fields_{namespace}_input = true | false
fields_{namespace}_output = true | false
fields_{namespace}_model = true | false
fields_{namespace}_defaultImport = "default import name" | true
fields_{namespace}_namespaceImport = "namespace import name"
fields_{namespace}_namedImport = true | false
}
Create configuration map in flatten style for {namespace}.
Where {namespace} is a namespace used in field triple slash comment.
fields_{namespace}_fromRequired. Name of the module, which will be used in import (class-validator, graphql-scalars, etc.)
Type: string
fields_{namespace}_inputMeans that it will be applied on input types (classes decorated by InputType)
Type: boolean
Default: false
fields_{namespace}_outputMeans that it will be applied on output types (classes decorated by ObjectType),
including models
Type: boolean
Default: false
fields_{namespace}_modelMeans that it will be applied only on model types (classes decorated by ObjectType)
Type: boolean
Default: false
fields_{namespace}_defaultImportDefault import name, if module have no namespace.
Type: undefined | string | true
Default: undefined
If defined as true then import name will be same as {namespace}
fields_{namespace}_namespaceImportImport all as this namespace from module
Type: undefined | string
Default: Equals to {namespace}
fields_{namespace}_namedImportIf imported module has internal namespace, this allow to generate named import,
imported name will be equal to {namespace}, see example of usage
Type: boolean
Default: false
Custom decorators example:
generator nestgraphql {
fields_Validator_from = "class-validator"
fields_Validator_input = true
}
model User {
id Int @id
/// @Validator.MinLength(3)
name String
}
May generate following class:
import { InputType, Field } from '@nestjs/graphql';
import * as Validator from 'class-validator';
@InputType()
export class UserCreateInput {
@Field(() => String, { nullable: false })
@Validator.MinLength(3)
name!: string;
}
Custom decorators can be applied on classes (models):
/// @NG.Directive('@extends')
/// @NG.Directive('@key(fields: "id")')
model User {
/// @NG.Directive('@external')
id String @id
}
generator nestgraphql {
fields_NG_from = "@nestjs/graphql"
fields_NG_output = false
fields_NG_model = true
}
May generate:
import * as NG from '@nestjs/graphql';
@NG.Directive('@extends')
@NG.Directive('@key(fields: "id")')
export class User {
@Field(() => ID, { nullable: false })
@NG.Directive('@external')
id!: string;
Allow set custom GraphQL scalar type for field
To override scalar type in specific classes, you can use glob pattern match: string | string[]
see outmatch for details.
model User {
id Int @id
/// @FieldType({ name: 'Scalars.GraphQLEmailAddress', from: 'graphql-scalars', input: true })
email String
}
May generate following class:
import { InputType, Field } from '@nestjs/graphql';
import * as Scalars from 'graphql-scalars';
@InputType()
export class UserCreateInput {
@Field(() => Scalars.GraphQLEmailAddress, { nullable: false })
email!: string;
}
And following GraphQL schema:
scalar EmailAddress
input UserCreateInput {
email: EmailAddress!
}
Same field type may be used in different models and it is not convenient to specify every time all options. There is a shortcut:
generator nestgraphql {
fields_Scalars_from = "graphql-scalars"
fields_Scalars_input = true
fields_Scalars_output = true
}
model User {
id Int @id
/// @FieldType('Scalars.GraphQLEmailAddress')
email String
}
The result will be the same. Scalars is the namespace here.
Missing field options will merged from generator configuration.
Similar to @FieldType() but refer to TypeScript property (actually field too).
To override TypeScript type in specific classes, you can use glob pattern match: string | string[]
see outmatch for details.
Example:
generator nestgraphql {
fields_TF_from = "type-fest"
}
model User {
id String @id
/// @PropertyType('TF.JsonObject')
data Json
}
May generate:
import * as TF from 'type-fest';
@ObjectType()
export class User {
@Field(() => GraphQLJSON)
data!: TF.JsonObject;
}
Allow attach @Directive decorator from @nestjs/graphql
GraphQL federation example:
/// @Directive({ arguments: ['@extends'] })
/// @Directive({ arguments: ['@key(fields: "id")'] })
model User {
/// @Directive({ arguments: ['@external'] })
id String @id
}
May generate:
@ObjectType()
@Directive('@extends')
@Directive('@key(fields: "id")')
export class User {
@Field(() => ID, { nullable: false })
@Directive('@external')
id!: string;
}
Allow rename type in schema and mark as abstract.
Example 1:
// schema.prisma
/// @ObjectType({ isAbstract: true })
model User {
id Int @id
}
@ObjectType({ isAbstract: true })
export class User {}
Example 2:
// schema.prisma
/// @ObjectType('Human', { isAbstract: true })
model User {
id Int @id
}
@ObjectType('Human', { isAbstract: true })
export class User {}
import { generate } from 'prisma-nestjs-graphql';
create-friendsMIT License (c) 2026