Introduction

Prisma is a next-generation developer-centric toolkit focused on making the data layer easy. This plugin gives you:

Workflow integration

Nexus build and dev workflows are enhanced to run your Prisma generators.

Runtime integration

Nexus schema component GraphQL type builders are augmented with .model and .crud methods. These make it easy for you to project your Prisma models and expose operations against them in your GraphQL API. Resolvers are dynamically created for you removing the need for traditional ORMs/query builders like TypeORM, Sequelize, or Knex. Out-of-box features include pagination, filtering, and ordering. And when you do need to drop down to custom resolvers a Prisma Client instance on context is ready to go.

Testtime integration

Nexus testing component is augmented with an instance of the Prisma Client, to help you easily seed your database for your tests.

Installation

  1. Install the plugin

    $npm add nexus-plugin-prisma

    Warning: All Prisma deps are bundled, so do not install e.g. @prisma/cli or @prisma/client. If you are wondering why you can read through Nexus' philosophy on dependency management. You can still find the the prisma CLI by running npm run prisma or yarn prisma. In an emergency you can still control version of prisma deps with Yarn "resolutions".

  2. Enable the plugin

    1import { use } from 'nexus'
    2import { prisma } from 'nexus-plugin-prisma'
    3
    4use(prisma())

Getting started

There are two ways you can start with the Prisma plugin. Either from scratch, or using an existing database.

From scratch

  1. Create a schema.prisma file

    1//schema.prisma
    2
    3generator prisma_client {
    4 provider = "prisma-client-js"
    5}
    6
    7model User {
    8 id Int @id @default(autoincrement())
    9 name String
    10}
  2. Add a datasource to your schema. We recommend you use Postgres but MySQL and SQLite are also supported.

    To add your datasource, simply copy/paste one of the block below at the top of your schema.prisma file

    Note: You can also pass the database credentials via a .env file. Read more about it here

    Using PostgreSQL:

    1//schema.prisma
    2
    3datasource db {
    4 provider = "postgres"
    5 url = "postgresql://USER:PASSWORD@localhost:5432/DATABASE"
    6}

    Using MySQL:

    1//schema.prisma
    2
    3datasource db {
    4 provider = "mysql"
    5 url = "mysql://USER:PASSWORD@localhost:3306/DATABASE"
    6}

    Using SQLite:

    1//schema.prisma
    2
    3datasource db {
    4 provider = "sqlite"
    5 url = "file:./dev.db"
    6}
  3. Create a migration file:

    $npm run prisma migrate save --experimental
  4. Migrate your database:

    $npm run prisma migrate up --experimental

You're ready to start working!

From an existing database

When starting from an existing database, you should use Prisma's introspection feature.

  1. Create a schema.prisma file.

    Create a schema.prisma file and add your database credentials in it so that Prisma can introspect your database schema.

    Note: You can also pass the database credentials via a .env file. Read more about it here

    Using PostgreSQL:

    1//schema.prisma
    2
    3datasource db {
    4 provider = "postgres"
    5 url = "postgresql://USER:PASSWORD@localhost:5432/DATABASE"
    6}

    Using MySQL:

    1//schema.prisma
    2
    3datasource db {
    4 provider = "mysql"
    5 url = "mysql://USER:PASSWORD@localhost:3306/DATABASE"
    6}

    Using SQLite:

    1//schema.prisma
    2
    3datasource db {
    4 provider = "sqlite"
    5 url = "file:./dev.db"
    6}
  2. Introspect your database:

    $npm run prisma introspect
  3. Generate the Prisma Client. Add the following block at the top of your schema.prisma file:

    1generator prisma_client {
    2 provider = "prisma-client-js"
    3}

    The plugin will take care of generating the Prisma Client for you after that.

You're ready to start working!

Example

Given a Prisma schema (left), you will be able to project these Prisma models onto your API and expose operations against them (middle) resulting in the GraphQL Schema (right).

Note: t.crud is an experimental feature. You must explicitly enable it via the plugin options.

1generator prisma_client {
2 provider = "prisma-client-js"
3}
4
5model User {
6 id String @id @default(cuid())
7 email String @unique
8 birthDate DateTime
9}
10
11model Post {
12 id String @id @default(cuid())
13 author User[]
14}
15
1import { schema } from 'nexus'
2
3schema.queryType({
4 definition(t) {
5 t.crud.user()
6 t.crud.users({
7 ordering: true,
8 })
9 t.crud.post()
10 t.crud.posts({
11 filtering: true,
12 })
13 },
14})
15
16schema.mutationType({
17 definition(t) {
18 t.crud.createOneUser()
19 t.crud.createOnePost()
20 t.crud.deleteOneUser()
21 t.crud.deleteOnePost()
22 },
23})
24
25schema.objectType({
26 name: 'User',
27 definition(t) {
28 t.model.id()
29 t.model.email()
30 t.model.birthDate()
31 t.model.posts()
32 },
33})
34
35schema.objectType({
36 name: 'Post',
37 definition(t) {
38 t.model.id()
39 t.model.author()
40 },
41})
1scalar DateTime
2
3input DateTimeFilter {
4 equals: DateTime
5 gt: DateTime
6 gte: DateTime
7 in: [DateTime!]
8 lt: DateTime
9 lte: DateTime
10 not: DateTime
11 notIn: [DateTime!]
12}
13
14type Mutation {
15 createOnePost(data: PostCreateInput!): Post!
16 createOneUser(data: UserCreateInput!): User!
17 deleteOnePost(where: PostWhereUniqueInput!): Post
18 deleteOneUser(where: UserWhereUniqueInput!): User
19}
20
21enum OrderByArg {
22 asc
23 desc
24}
25
26type Post {
27 author(after: String, before: String, first: Int, last: Int): [User!]!
28 id: ID!
29}
30
31input PostCreateInput {
32 author: UserCreateManyWithoutAuthorInput
33 id: ID
34}
35
36input PostCreateManyWithoutPostsInput {
37 connect: [PostWhereUniqueInput!]
38 create: [PostCreateWithoutAuthorInput!]
39}
40
41input PostCreateWithoutAuthorInput {
42 id: ID
43}
44
45input PostFilter {
46 every: PostWhereInput
47 none: PostWhereInput
48 some: PostWhereInput
49}
50
51input PostWhereInput {
52 AND: [PostWhereInput!]
53 author: UserFilter
54 id: StringFilter
55 NOT: [PostWhereInput!]
56 OR: [PostWhereInput!]
57}
58
59input PostWhereUniqueInput {
60 id: ID
61}
62
63type Query {
64 post(where: PostWhereUniqueInput!): Post
65 posts(after: String, before: String, first: Int, last: Int, where: PostWhereInput): [Post!]!
66 user(where: UserWhereUniqueInput!): User
67 users(after: String, before: String, first: Int, last: Int, orderBy: UserOrderByInput): [User!]!
68}
69
70input StringFilter {
71 contains: String
72 endsWith: String
73 equals: String
74 gt: String
75 gte: String
76 in: [String!]
77 lt: String
78 lte: String
79 not: String
80 notIn: [String!]
81 startsWith: String
82}
83
84type User {
85 birthDate: DateTime!
86 email: String!
87 id: ID!
88 posts(after: String, before: String, first: Int, last: Int): [Post!]!
89}
90
91input UserCreateInput {
92 birthDate: DateTime!
93 email: String!
94 id: ID
95 posts: PostCreateManyWithoutPostsInput
96}
97
98input UserCreateManyWithoutAuthorInput {
99 connect: [UserWhereUniqueInput!]
100 create: [UserCreateWithoutPostsInput!]
101}
102
103input UserCreateWithoutPostsInput {
104 birthDate: DateTime!
105 email: String!
106 id: ID
107}
108
109input UserFilter {
110 every: UserWhereInput
111 none: UserWhereInput
112 some: UserWhereInput
113}
114
115input UserOrderByInput {
116 birthDate: OrderByArg
117 email: OrderByArg
118 id: OrderByArg
119}
120
121input UserWhereInput {
122 AND: [UserWhereInput!]
123 birthDate: DateTimeFilter
124 email: StringFilter
125 id: StringFilter
126 NOT: [UserWhereInput!]
127 OR: [UserWhereInput!]
128 posts: PostFilter
129}
130
131input UserWhereUniqueInput {
132 email: String
133 id: ID
134}

Plugin settings

You can optionally pass some settings to the plugin.

Type definition

1export type PrismaClientOptions = {
2 /**
3 * Options to pass to the Prisma Client instantiated by the plugin.
4 * If you want to instantiate your own Prisma Client, use `instance` instead.
5 */
6 options: ClientOptions
7}
8
9export type PrismaClientInstance = {
10 /**
11 * Instance of your own Prisma Client. You can import it from 'nexus-plugin-prisma/client'.
12 * If you just want to pass some settings to the Prisma Client, use `options` instead.
13 */
14 instance: PrismaClient
15}
16
17export type Settings = {
18 /**
19 * Use this to pass some settings to the Prisma Client instantiated by the plugin or to pass your own Prisma Client
20 */
21 client?: PrismaClientOptions | PrismaClientInstance
22 /**
23 * Enable or disable migrations run by the plugin when editing your schema.prisma file
24 *
25 * @default true
26 */
27 migrations?: boolean
28 /**
29 * Features that require opting into. These are all disabled by default.
30 */
31 features?: {
32 /**
33 * Enable **experimental** CRUD capabilities.
34 * Add a `t.crud` method in your definition block to generate CRUD resolvers in your `Query` and `Mutation` GraphQL Object Type.
35 *
36 * @default false
37 */
38 crud?: boolean
39 }
40}

Examples

Configuring the Prisma Client

1import { use } from 'nexus'
2import { prisma } from 'nexus-plugin-prisma'
3
4use(
5 prisma({
6 client: { options: { log: ['query'] } },
7 })
8)

Using a custom instance of the Prisma Client

1import { use } from 'nexus'
2import { prisma } from 'nexus-plugin-prisma'
3import { PrismaClient } from 'nexus-plugin-prisma/client'
4
5use(
6 prisma({
7 client: { instance: new PrismaClient() },
8 })
9)

Recipes

Projecting Prisma model fields

Exposing one of your Prisma models in your GraphQL API

1schema.objectType({
2 name: 'Post',
3 definition(t) {
4 t.model.id()
5 t.model.title()
6 t.model.content()
7 },
8})

Simple computed GraphQL fields

You can add computed fields to a GraphQL object using the standard GraphQL Nexus API.

1schema.objectType({
2 name: "Post",
3 definition(t) {
4 t.model.id()
5 t.model.title()
6 t.model.content()
7 t.string("uppercaseTitle", {
8 resolve({ title }, args, ctx) {
9 return title.toUpperCase(),
10 }
11 })
12 },
13})

Complex computed GraphQL fields

If you need more complicated logic for your computed field (e.g. have access to some information from the database), you can use the prisma instance that's attached to the context and implement your resolver based on that.

1schema.objectType({
2 name: 'Post',
3 definition(t) {
4 t.model.id()
5 t.model.content()
6 t.string('anotherComputedField', {
7 async resolve(_parent, _args, ctx) {
8 const databaseInfo = await ctx.prisma.someModel.someOperation(...)
9 const result = doSomething(databaseInfo)
10 return result
11 }
12 })
13 }
14})

Project a Prisma field to a differently named GraphQL field

1schema.objectType({
2 name: 'Post',
3 definition(t) {
4 t.model.id()
5 t.model.content({
6 alias: 'body',
7 })
8 },
9})

t.crud is an experimental feature. You must explicitly enable it via the plugin options.

1schema.queryType({
2 definition(t) {
3 t.crud.post()
4 t.crud.posts({
5 ordering: true,
6 filtering: true,
7 })
8 },
9})

Publish writes on a Prisma model

t.crud is an experimental feature. You must explicitly enable it via the plugin options.

1schema.mutationType({
2 definition(t) {
3 t.crud.createPost()
4 t.crud.updatePost()
5 t.crud.updateManyPost()
6 t.crud.upsertPost()
7 t.crud.deletePost()
8 t.crud.deleteManyPost()
9 },
10})

Publish customized reads on a Prisma model

t.crud is an experimental feature. You must explicitly enable it via the plugin options.

1schema.queryType({
2 definition(t) {
3 t.crud.posts({
4 filtering: {
5 id: true,
6 title: true,
7 },
8 ordering: { title: true },
9 })
10 },
11})

Publish autogenerated mutations with computed input values

t.crud is an experimental feature. You must explicitly enable it via the plugin options.

1schema.mutationType({
2 definition(t) {
3 /*
4 Assuming our prisma model for User has a createdByBrowser field,
5 this removes it from the input type but ensures the value is
6 inferred from context and passed to Prisma Client.
7 */
8 t.crud.createOneUser({
9 computedInputs: {
10 createdByBrowser: ({ args, ctx, info }) => ctx.session.browser,
11 },
12 })
13 },
14})

Globally remove a field from input types and infer its value

🚧 Work in progress.

Note Not yet possible in framework.

1nexusPrismaPlugin({
2 ...other config...
3 /*
4 Remove fields named "user" from all input types. When resolving
5 a request whose data contains any of these types, the value is inferred
6 from context and passed to Prisma Client, even if it's nested. This is great for
7 creating data associated with one user's account.
8 */
9 computedInputs: {
10 user: ({ args, ctx, info }) => ({
11 connect: {
12 id: ctx.userId,
13 },
14 }),
15 },
16})
1schema.mutationType({
2 definition(t) {
3 t.crud.createOnePost()
4 },
5})

Without computedInputs:

1mutation createOnePost {
2 createOnePost(
3 data: {
4 title: "Automatically generate clean APIs!"
5 image: { url: "https://example.com/images/prancing-unicorns", user: { connect: { id: 1 } } }
6 user: { connect: { id: 1 } }
7 }
8 )
9}

With computedInputs:

1mutation createOnePost {
2 createOnePost(
3 data: {
4 title: "Automatically generate clean APIs!"
5 image: { url: "https://example.com/images/prancing-unicorns" }
6 }
7 )
8}

Publish model writes along side Prisma Client-resolved fields

t.crud is an experimental feature. You must explicitly enable it via the plugin options.

1schema.mutationType({
2 definition(t) {
3 t.crud.createUser()
4 t.crud.updateUser()
5 t.crud.deleteUser()
6 t.crud.deletePost()
7
8 t.field('createDraft', {
9 type: 'Post',
10 args: {
11 title: stringArg(),
12 content: stringArg({
13 nullable: true,
14 }),
15 },
16 resolve: (parent, { title, content }, ctx) => {
17 return ctx.prisma.posts.createPost({ title, content })
18 },
19 })
20
21 t.field('publish', {
22 type: 'Post',
23 nullable: true,
24 args: {
25 id: idArg(),
26 },
27 resolve(parent, { id }, ctx) {
28 return ctx.prisma.posts.updatePost({
29 where: { id },
30 data: {
31 published: true,
32 },
33 })
34 },
35 })
36 },
37})
Edit this page on Github