Use Prisma

  1. Install the prisma plugin

    $npm add nexus-plugin-prisma
  2. Enable the plugin

    1import { use } from 'nexus'
    2import { prisma } from 'nexus-plugin-prisma'
    3
    4use(prisma())
  3. Add a schema.prisma file. Add a datasource. Here we're working with SQLite. Add Prisma Client.

    ++ prisma/schema.prisma
    +
    + datasource db {
    + provider = "sqlite"
    + url = "file:dev.db"
    + }
    +
    + generator prisma_client {
    + provider = "prisma-client-js"
    + }
  4. Initialize your database

    $yarn prisma migrate save --experimental && yarn prisma migrate up --experimental

Your app now includes the following:

t.model and t.crud field builders e.g.:

1```ts
+++ src/graphql.ts
3 objectType({
4 name: 'User',
5 definition(t) {
- t.id('id)
- t.string('name')
+ t.model.id()
+ t.model.name()
10 },
11 })
12```

An instance of the generated Prisma Client is a added to context under the db property, allowing e.g.:

1```ts
+++ src/graphql.ts
3 queryType({
4 definition(t) {
5 t.list.field('users', {
6 type: 'User',
- resolve() {
- return [{ id: '1643', name: 'newton' }]
+ resolve(_root, _args, ctx) {
+ return ctx.db.users.findMany()
11 },
12 })
13 },
14 })
15```

The TypeScript types representing your Prisma models are registered as a Nexus data source. In short this enables proper typing of parent parameters in your resolves. They reflect the data of the correspondingly named Prisma model.

Create a consumable plugin

  1. Scaffold Your plugin project

    $npx nexus create plugin
  2. Publish it

    $yarn publish

Setting up PostgreSQL

Hosted

For trying things out in a deployed setting you can try Heroku's free postgres tier. Setting it up is simple:

$heroku create
$heroku addons:create heroku-postgresql
$
$# Now get the connection URL
$heroku pg:credentials:url

For a more complete explanation of this approach see this blog post by Nikolas Burk using the the Heroku UI.

Local

The recommended way to run postgres locally is with docker, because it is easy flexible and reliable.

  1. Start a postgres server for your app:

    $docker run --detach --publish 5432:5432 -e POSTGRES_PASSWORD=postgres --name 'postgres' postgres:10.12
  2. Now you can use a connection URL like:

    1postgresql://postgres:postgres@localhost:5432/myapp

If you don't want to use a docker, here are some links to alternative approaches for macOS users:

Go to production

  1. Add a build script

    +++ package.json
    + "build": "nexus build"
  2. Add a start script

    +++ package.json
    + "start": "node .nexus/build/api"
  3. In many cases this will be enough. Many deployment platforms will call into these scripts by default. You can customize where build outputs to if your deployment platform requires it. There are built in guides for vercel and heroku which will check your project is prepared for deployment to those respective platforms. Take advantage of them if applicable:

    +++ package.json
    + "build": "nexus build --deployment vercel"
    +++ package.json
    + "build": "nexus build --deployment heroku"

Prisma + Heroku + PostgreSQL

  1. Confirm the name of the environment variable that Heroku will inject into your app at runtime for the database connection URL. In a simple setup, with a single attached database, it is DATABASE_URL.

  2. Update your Prisma Schema file to get the database connection URL from an environment variable of the same name as in step 1. Example:

    -- prisma/schema.prisma
    2+++ prisma/schema.prisma
    3 datasource postgresql {
    4 provider = "postgresql"
    - url = "postgresql://<user>:<pass>@localhost:5432/<db-name>"
    + url = env("DATABASE_URL")
    7 }
  3. Update your local development environment to pass the local development database connection URL via an environment variable of the same name as in step 1.

    Example with direnv:

    1. Install direnv

      $brew install direnv
    2. Hook direnv into your shell (instructions)

    3. Setup an .envrc file inside your project

      +++ .envrc
      + DATABASE_URL="postgresql://postgres:postgres@localhost:5432/myapp"
    4. Approve the .envrc file (one time, every time the envrc file changes).

      $direnv allow .
    5. Done. Now when you work within your project with a shell, all your commands will be run with access to the environment variables defined in your .envrc file. The magic of direnv is that these environment variables are automatically exported to and removed from your environment based on you being within your project directory or not.

Integrate createTestContext with jest

  1. Wrap createTestContext so that it is integrated with the jest test suite lifecycle hooks:

    1// tests/__helpers.ts
    2import { createTestContext, TestContext } from 'nexus/testing'
    3
    4export function createTestContext(): TestContext {
    5 let ctx: TestContext
    6
    7 beforeAll(async () => {
    8 Object.assign(ctx, await createTestContext())
    9 await ctx.app.start()
    10 })
    11
    12 afterAll(async () => {
    13 await ctx.app.stop()
    14 })
    15
    16 return ctx
    17}
  2. Import your wrapped version into all test suites needing it:

    1// tests/foo.spec.ts
    2import { createTestContext } from './__helpers'
    3
    4const ctx = createTestContext()
    5
    6it('foo', () => {
    7 // use `ctx` in here
    8})

    Note that ctx is not usable outside of jest blocks (it before after ...). If you try to you'll find it to be undefined.

    1import { createTestContext } from './__helpers'
    2
    3const { app } = createTestContext() // Error!

Debugging

With VS Code

We made it very simple to debug your app with VS Code.

Note: If you used npx nexus to initialize your project, jump straight to step 2.

  1. Create a .vscode/launch.json file and paste the following content

    1{
    2 "version": "0.2.0",
    3 "configurations": [
    4 {
    5 "type": "node",
    6 "request": "launch",
    7 "name": "Debug Nexus App",
    8 "protocol": "inspector",
    9 "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/nexus",
    10 "runtimeArgs": ["dev"],
    11 "sourceMaps": true,
    12 "console": "integratedTerminal"
    13 }
    14 ]
    15}
  2. Click on the Run tab on the left side of VS Code

  3. Make sure Debug Nexus App is selected in the dropdown located at the top of the panel that the Run tab opened

  4. Set some breaking points where you want to inspect your code

  5. Click the green "Start debugging" button located next to the dropdown

  6. That's it. VS Code should run your code and stop wherever your set some breakpoints

Use with Next.js

Find working examples here.

Steps

  1. Your Next.js project must be a TypeScript, not JavaScript, one

  2. Install nexus

  3. Create one GraphQL endpoint, e.g. <project root>/pages/api/graphql.ts

  4. The minimum boilerplate needed in your GraphQL endpoint is:

    1// <project root>/pages/api/graphql.ts
    2
    3if (process.env.NODE_ENV === 'development') require('nexus').default.reset()
    4
    5const app = require('nexus').default
    6
    7// Require your nexus modules here.
    8// Do not write them inline, since the Nexus API is typed `any` because of `require` import.
    9// require('...')
    10
    11app.assemble()
    12
    13export default app.server.handlers.graphql
  5. While developing, you should run Nexus reflection a separate terminal apart from your normal next dev. This is in order to benefit from the type safety that Nexus can give you. One of its primary benefits. For example:

    1"nexus:reflection": "nexus dev --reflection --entrypoint pages/api/graphql.ts",
  6. With compilerOptions.noEmit set to true in your tsconfig (forced by Next.js), treat nexus build as a check step in your ci process.

Notes

Overall, here are the limitations with Next.js integration that you will not find in a "normal" Nexus project.

  1. You must use CommonJS require as opposed to ES module import syntax for your Nexus api module. This is to preserve import order.
  2. You must run app.assemble() before accessing the server handlers.
  3. In development, you must run app.reset() in your Nexus api module, before anything else.
  4. Make sure that you only have one Nexus api module, or else you may experience difficulties in development.
  5. Make sure that your Nexus modules (ones using the nexus package) are only part of the import graph of your Nexus api module.
  6. You will not be able to use the Nexus testing component

Integration with Next.js should improve once it supports plugins. For example you will probably not need to think about app.assemble() and app.reset() anymore and be able to use ES module syntax in your Nexus api module.

Edit this page on Github