---
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. You'll learn about:

- Prisma
- Setting up a Postgres database locally

We're going to be using a database called Postgres and a tool called Prisma to interact with it.

Postgres is a well known open-source relational database. 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** (experimental): 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 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.

## Connect to your database

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

- Install the Prisma Client & the Prisma CLI
- Use it in your `api/schema.ts` module
- Create your Prisma Schema
- Create a `.env` file to store your database credentials
- Connect to your database

like so:

```bash-symbol
npm add @prisma/client && npm add --save-dev @prisma/cli
```

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

Almost done, but we still need to setup a Postgres database for our app to connect to. There are a ton of ways to do this so we're just going to show the most straight forward cross-platform way we know how. First, make sure you have [docker installed](https://docs.docker.com/get-docker/). Then, simply run this command:

```bash-symbol
docker run --detach --publish 5432:5432 -e POSTGRES_PASSWORD=postgres --name nexus-tutorial-postgres postgres:10
```

That's it. You now have a Postgres server running.

If you prefer setting up your local Postgres another way go for it. If our suggest approach doesn't work for you, then checkout a few other approaches listed on the [Nexus recipes page](https://www.nexusjs.org/#/references/recipes?id=setting-up-postgresql).

Finally, in the `prisma/.env` file you've created before, replace `<postgres_connection_url>` with your actual database URL.

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

```diff
-DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
+DATABASE_URL="postgresql://postgres:postgres@localhost:5432/myapp"
```

</tab>
<tab>

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


</tab>
</TabbedContent>

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

## Create your database schema

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>

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

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

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

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

</tab>
<tab>

```groovy
// prisma/schema.prisma

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

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-symbold
npx prisma migrate dev --preview-feature
```

## 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
// 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
// api/context.ts
import { db } from "./db";
import { PrismaClient } from "@prisma/client"

export interface Context {
  db: PrismaClient
}

export const context = {
  db,
}
```

</tab>
</TabbedContent>

Finally, generate the PrismaClient using the Prisma CLI

```bash-symbol
npx prisma generate
```

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 postToPublish = ctx.db.posts.find((p) => p.id === args.draftId)

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

-       postToPublish.published = true

-       return postToPublish

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

</tab>
<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.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>
