---
title: 5. Persisting data (via Prisma)
---

## Overview

So far we have been working with in-memory data while we learn about other parts of Nexus in a focused manner, but in this chapter we're going to put the focus squarely on data and show how Nexus can be used with a database. This marks an important step toward your blog app becoming more real. 

In this section, you'll learn how to add Prisma to your GraphQL API.
Prisma is a new way of working with databases that we'll learn more about in a moment.

Its important to understand that Nexus does not _require_ these technology choices and _could_ actually be used with any database and abstractions over them (raw SQL, query builder, ORM..). However, Nexus is built by a team at Prisma (the company) and unsurprisingly there is great integration between its tools and Nexus.

## What is Prisma?

So, what _is_ Prisma? It is an open source database toolkit that consists of the following parts:

- **Prisma Client**: Auto-generated and type-safe query builder for Node.js & TypeScript
- **Prisma Migrate** (Preview): Declarative data modeling & migration system
- **Prisma Studio**: GUI to view and edit data in your database

At the heart of Prisma is the _Prisma Schema,_ a file usually called `schema.prisma`, that you will see later in this tutorial. It is a declarative file wherein using a domain specific language you encode your database schema, connection to the database, and more.
Prisma currently supports 4 relational databases: MySQL, PostgreSQL, SQL Server and SQLite.

Prisma has great [docs](https://www.prisma.io/docs/understand-prisma/introduction) so definitely check them out at some point. For now you can stay in the flow of this tutorial if you want though. We're going to focus on Prisma Client.

## Set up Prisma

Now that you know a bit about Prisma, let's get going! Do the following:

- Install the Prisma client and CLI
- Use it in your `api/schema.ts` module
- Create your Prisma Schema

like so:

```bash-symbol copy
npm install @prisma/client
npm install --save-dev prisma
```

Next, add Prisma to your project by creating your [Prisma schema](https://www.prisma.io/docs/concepts/components/prisma-schema/) file with the following command:

```bash-symbol copy
npx prisma init
```

The command creates a new directory called `prisma` which will contain a `schema.prisma` file and add a `.env` file at the root of your project.

For ease of set up, this guide will use SQLite. If you wish to use your preferred database, you can make the switch by simply changing the `provider` and `url` in your `schema.prisma` file.

To connect to your database, you'll need to set the `url` field in the `datasource` block in your Prisma schema. 
Since the `url` is set via an environment variable, you will define it in `.env`. 

```diff
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/myapp"
```

<!-- **TODO: find a way to make sure their connection url is working**
Confirm things are setup correctly by ...
-->

## Create your first database model

It is now time to replace our in-memory data with actual tables in our database. To do this we'll write models in our Prisma Schema.

In chapters 2 and 3 we already began to model our blog domain with the GraphQL type `Post`. We can base our models on that prior work, resulting in a Prisma Schema like so:

<TabbedContent tabs={['Diff', 'Code']}>
<tab>

```prisma diff
// prisma/schema.prisma

datasource db {
+  provider = "sqlite"
+  url      = "file:./dev.db"
}

generator client {
  provider = "prisma-client-js"
}

+model Post {
+  id        Int     @id @default(autoincrement())
+  title     String
+  body      String
+  published Boolean
+}
```

</tab>
<tab>

```prisma
// prisma/schema.prisma

datasource db {
  provider = "sqlite"
  url      = "file:./dev.db"
}

generator client {
  provider = "prisma-client-js"
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  body      String
  published Boolean
}
```

</tab>
</TabbedContent>

With our database schema specified, we're now ready to proceed to our first database migration! To do that, we'll use the Prisma CLI.

```bash-symbol copy
npx prisma migrate dev --name init --preview-feature
```

This will create a database migration called `init`. Once a migration is complete, the Prisma CLI will create `dev.db` database and apply the changes against your database.
Once the first migration is complete, the Prisma CLI will install `@prisma/client` package. In subsequent migrations, Prisma CLI will generate the Prisma Client.

## Access your database

Now let's finally ditch our in-memory data! Let's replace it with the Prisma Client

<TabbedContent tabs={['Diff', 'Code']}>
<tab>

```ts
// api/db.ts
+import { PrismaClient } from '@prisma/client'

+export const db = new PrismaClient()

-export interface Post {
-  id: number
-  title: string
-  body: string
-  published: boolean
-}

-export interface Db {
-  posts: Post[]
-}

-export const db: Db = {
-  posts: [{ id: 1, title: 'Nexus', body: '...', published: false }],
-}
```

</tab>
<tab>

```ts copy
// api/db.ts
import { PrismaClient } from '@prisma/client'

export const db = new PrismaClient()
```

</tab>
</TabbedContent>


Then, update your `Context` type so that it uses the PrismaClient created in `./db.ts`

<TabbedContent tabs={['Diff', 'Code']}>
<tab>

```ts
// api/context.ts
import { db } from "./db";
+import { PrismaClient } from "@prisma/client"

export interface Context {
-  db: Db
+  db: PrismaClient
}

export const context = {
  db,
}
```

</tab>
<tab>

```ts copy
// api/context.ts
import { db } from "./db";
import { PrismaClient } from "@prisma/client"

export interface Context {
  db: PrismaClient
}

export const context = {
  db,
}
```

</tab>
</TabbedContent>


Let's now replace all our previous in-memory db interactions with calls to the Prisma Client

<TabbedContent tabs={['Diff', 'Code']}>
<tab>

```ts
// api/graphql/Post.ts
// ...

export const PostQuery = extendType({
  type: 'Query',
  definition(t) {
    t.list.field('drafts', {
      type: 'Post',
      resolve(_root, _args, ctx) {
-        return ctx.db.posts.filter((p) => p.published === false)
+        return ctx.db.post.findMany({ where: { published: false } })
      },
    });
    t.list.field('posts', {
      type: 'Post',
      resolve(_root, _args, ctx) {
-       return ctx.db.posts.filter((p) => p.published === true)
+       return ctx.db.post.findMany({ where: { published: true } })
      },
    })
  },
})

export const PostMutation = extendType({
  type: 'Mutation',
  definition(t) {
    t.field('createDraft', {
      type: 'Post',
      args: {
        title: nonNull(stringArg()),
        body: nonNull(stringArg()),
      },
      resolve(_root, args, ctx) {
        const draft = {
-         id: ctx.db.posts.length + 1,
          title: args.title,
          body: args.body,
          published: false,
        }
-       ctx.db.posts.push(draft)

-       return draft
+       return ctx.db.post.create({ data: draft })
      },
    })

    t.field('publish', {
      type: 'Post',
      args: {
        draftId: nonNull(intArg()),
      },
      resolve(_root, args, ctx) {
-       let draftToPublish = ctx.db.posts.find((p) => p.id === args.draftId)

-       if (!draftToPublish) {
-         throw new Error('Could not find draft with id ' + args.draftId)
-       }

-       draftToPublish.published = true

-       return draftToPublish

+       return ctx.db.post.update({
+         where: { id: args.draftId },
+         data: {
+           published: true,
+         },
+       });
      },
    })
  },
})
```

</tab>
<tab>

```ts copy
// api/graphql/Post.ts
// ...

export const PostQuery = extendType({
  type: 'Query',
  definition(t) {
    t.list.field('drafts', {
      type: 'Post',
      resolve(_root, _args, ctx) {
        return ctx.db.post.findMany({ where: { published: false } })
      },
    })
    t.list.field('posts', {
      type: 'Post',
      resolve(_root, _args, ctx) {
        return ctx.db.post.findMany({ where: { published: true } })
      },
    })
  },
})

export const PostMutation = extendType({
  type: 'Mutation',
  definition(t) {
    t.field('createDraft', {
      type: 'Post',
      args: {
        title: nonNull(stringArg()),
        body: nonNull(stringArg()),
      },
      resolve(_root, args, ctx) {
        const draft = {
          title: args.title,
          body: args.body,
          published: false,
        }
        return ctx.db.post.create({ data: draft })
      },
    })

    t.field('publish', {
      type: 'Post',
      args: {
        draftId: nonNull(intArg()),
      },
      resolve(_root, args, ctx) {
        return ctx.db.post.update({
          where: {
            id: args.draftId
          },
          data: {
            published: true,
          },
        })
      },
    })
  },
})
```
</tab>
</TabbedContent>

## Try it out

Awesome, you're ready to open up the playground and create a draft! If all goes well, good job! If not, no worries, there's a lot of integration pieces in this chapter where something could have gone wrong. If after reviewing your steps you still don't understand the issue, feel free to open up a [discussion](https://nxs.li/discussions) asking for help.

## Wrapping up

We've just changed our code, so we must be due or overdue for a test update right? Well, in the next chapter we'll do just that, and show you how Nexus testing works with Prisma.

<ButtonLink
  color="dark"
  type="primary"
  href="/getting-started/tutorial/chapter-testing-with-prisma"
>
  Next &rarr;
</ButtonLink>
