Next.js, Prisma, PlanetScale and Vercel

Deploy your Next.js + Prisma app to PlanetScale and Vercel

Concepts

First, let's go over the main concepts of Prisma and PlanetScale.

  1. Prisma Migrate: Takes your schema changes and applies them to your database.
  2. PlanetScale Branches: Just like git branches: with a main (production) branch and development branches. Schema changes cannot be made directly on the main branch.
  3. PlanetScale Deploy Request: Like git pull requests but for development branches againts the production branch. You don't make schema changes on your main branch. You use deploy requests.
  4. Shadow Database: A temporary database used by prisma migrate to protect and detect manual changes (schema drift) on the development database.

Branches and Deploy Requests

Here's how it works:

When you first deploy your app to Vercel, Prisma will try to run prisma migrate against your connected database on the production branch.

Since schema changes cannot be made to the production branch, you will see the following error:

16:09:50.549 Error: P3018

16:09:50.550 Direct execution of DDL (Data Definition Language) SQL statements is disabled on this database. Please read more here how to handle this: https://pris.ly/d/migrate-no-direct-ddl

To fix this:

  1. We are going to run prisma migrate on a development branch.
  2. Then we'll create a deploy request againts the main branch.
  3. We'll merge the deploy request to apply the schema changes.
Prisma + PlanelScale

Prerequisites

  1. Turn on Automatically copy migration data on your database Settings page on PlanetScale.
  2. Install the PlanetScale CLI
PlanelScale Settings

Workflow

The following commands and code changes are done on your local machine from the root of your Next.js app.

Update schema.prisma

Update your schema.prisma file and enable referentialIntegrity (previously called planetScaleMode - thanks @brian_lovin).

datasource db {
  provider          = "mysql"
  url               = env("DATABASE_URL")
+  shadowDatabaseUrl = env("SHADOW_DATABASE_URL")
+  referentialIntegrity = "prisma"
}
 
generator client {
  provider        = "prisma-client-js"
+  previewFeatures = ["referentialIntegrity"]
}
datasource db {
  provider          = "mysql"
  url               = env("DATABASE_URL")
+  shadowDatabaseUrl = env("SHADOW_DATABASE_URL")
+  referentialIntegrity = "prisma"
}
 
generator client {
  provider        = "prisma-client-js"
+  previewFeatures = ["referentialIntegrity"]
}

Commit and push these schema.prisma changes.

Apply schema changes

  1. Login to PlanetScale
pscale auth login
pscale auth login
  1. Create two development branches (one to run the initial migrations and one as a shadow branch).
pscale branch create NAME-OF-YOUR-DATABASE init
 
pscale branch create NAME-OF-YOUR-DATABASE shadow
pscale branch create NAME-OF-YOUR-DATABASE init
 
pscale branch create NAME-OF-YOUR-DATABASE shadow
  1. Update your .env file and add the following (If you already have a local DATABASE_URL configured, you can temporarily comment it out):
DATABASE_URL="mysql://root@127.0.0.1:3309/NAME-OF-YOUR-DATABASE"
SHADOW_DATABASE_URL="mysql://root@127.0.0.1:3310/NAME-OF-YOUR-DATABASE"
DATABASE_URL="mysql://root@127.0.0.1:3309/NAME-OF-YOUR-DATABASE"
SHADOW_DATABASE_URL="mysql://root@127.0.0.1:3310/NAME-OF-YOUR-DATABASE"
  1. Connect to the init branch.
pscale connect NAME-OF-YOUR-DATABASE init --port 3309
pscale connect NAME-OF-YOUR-DATABASE init --port 3309
  1. In another terminal, connect to the shadow branch.
pscale connect NAME-OF-YOUR-DATABASE shadow --port 3310
pscale connect NAME-OF-YOUR-DATABASE shadow --port 3310
  1. Run the migrations.
yarn prisma migrate dev
yarn prisma migrate dev

Create deploy request.

The init branch now has your initial schema. To apply this schema to the main branch, we'll create a deploy request.

  1. Create a deploy request:
pscale deploy-request create NAME-OF-YOUR-DATABASE init
pscale deploy-request create NAME-OF-YOUR-DATABASE init

Once the deploy request is created you can visit your PlanelScale dashboard to see the request and the schema changes.

  1. Merge the deploy request:
pscale deploy-request deploy NAME-OF-YOUR-DATABASE DEPLOY-REQUEST-NUMBER
pscale deploy-request deploy NAME-OF-YOUR-DATABASE DEPLOY-REQUEST-NUMBER

Since this is your first deploy request, the DEPLOY-REQUEST-NUMBER is 1.

You have now successfully deploy the initial schema to your main branch.

You may safely remove the DATABASE_URL and SHADOW_DATABASE_URL from your .env file and delete the development branches.

pscale branch delete NAME-OF-YOUR-DATABASE init
 
pscale branch delete NAME-OF-YOUR-DATABASE shadow
pscale branch delete NAME-OF-YOUR-DATABASE init
 
pscale branch delete NAME-OF-YOUR-DATABASE shadow

Deploy to Vercel

Now that your database is ready, you can deploy your Next.js app to Vercel.

PlanelScale Integration

Enable the PlanelScale integration from your Vercel dashboard under Integrations.

Connect database

Database Connection
  1. Visit your PlanetScale database page.
  2. Click on Connect.
  3. Select Prisma under Format.
  4. Copy the url.
  5. Replace sslcert=/etc/ssl/cert.pem with sslcert=/etc/pki/tls/certs/ca-bundle.crt.
  6. Add this url as an environment variable named DATABASE_URL on Vercel.

Deploy

You are now ready to deploy.

vercel deploy --prod
vercel deploy --prod

#vercelconfetti 🎉