Nx — Model With Prisma

Data makes the world go around so they say. In this article I detail how I use Prisma with Nx to maintain my data models. It is an approach that keeps the model isolated from the underlying “implementation details” and keeps me sane when things in the model need to change.

A few assumptions about who you are first:
- you know enough SQL to be dangerous
- you have played with Nx a bit and understand what the workspace.json file is and what it does and have some comfort making manual changes to it
- you have some concept of what a database migration is
- you have an Nx workspace setup

Part 1: Setting Up Your Nx Project

It may be worth your while to read at least this page of the Prisma docs
The model type that I will explain below makes use of the experimental migrations that Prisma offers.

npm install @prisma/cli -D

Ok, the prisma lib is now available, great so now what? Well, lets create a nest library (I am using nest but really you could just create a node library).

npx nx g @nrwl/nest:library models

Next, inside the <project>/libs/models/src directory, create a new directory called “prisma” and then in that new directory create a file called “prisma.schema”. For this article, we will just use the sample schema that Prisma has in their docs. So, my prisma.schema looks like:

datasource db {
url = env("DATABASE_URL")
provider = "postgres"
}
generator client {
provider = "prisma-client-js"
output = "../../node_modules/.prisma/client"
}
model User {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
email String @unique
name String?
role Role @default(USER)
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
published Boolean @default(false)
title String
author User? @relation(fields: [authorId], references: [id])
authorId Int?
}
enum Role {
USER
ADMIN
}

Part 2: Connecting to the database

Those with a keen eye will notice the use of an env var. Lets take care of that right now. In the <project>/libs/models directory, create a file called .env, in the .env file put the following:

DATABASE_URL=postgres://postgres:mysecretpassword@localhost:5432/postgres

“Wait! I don’t have a postgres server running!” — if this is you then I trust you at least have docker installed on your system? I hope so, if not its simple to install — check out this link to get it setup on your system. Then all you need to run is:

docker pull postgres
docker run -p 5432:5432 --name some-postgres -e POSTGRES_PASSWORD=mysecretpassword -d postgres

Great, now docker is running an instance of postgres for us (note the password matches what we put into the .env?) There is one more thing we need to setup. Open your project workspace.json and locate the “models” library section (it should look like this):

...
"models": {
"root": "libs/models",
"sourceRoot": "libs/models/src",
"projectType": "library",
"schematics": {},
"architect": {
"lint": {
"builder": "@nrwl/linter:eslint",
"options": {
"lintFilePatterns": ["libs/models/**/*.ts"]
}
},
"test": {
"builder": "@nrwl/jest:jest",
"options": {
"jestConfig": "libs/models/jest.config.js",
"passWithNoTests": true
}
}
}
...

Lets add some new commands to the lib which will make it super easy to create new model migrations, update the database with the migrations and generate the client code for use of the model. Add the following after the “test” architecture:

...
"test":{...},
"migrate-save": {
"builder": "@nrwl/workspace:run-commands",
"outputs": [],
"options": {
"command": "npx prisma migrate save --experimental --schema ./src/prisma/prisma.schema",
"cwd": "libs/models"
}
},
"migrate-up": {
"builder": "@nrwl/workspace:run-commands",
"outputs": [],
"options": {
"command": "npx prisma migrate up --experimental --schema ./src/prisma/prisma.schema",
"cwd": "libs/models"
}
},
"gen-client": {
"builder": "@nrwl/workspace:run-commands",
"outputs": [],
"options": {
"command": "npx prisma generate --schema ./src/prisma/prisma.schema",
"cwd": "libs/models"
}
}
...

Part 3: Using our new commands

Now from a terminal go to the root of your project and run:

npx nx run models:migrate-save

It will ask you to name the migration. Once it completes you will have a new directory in the <project-root>/models/src/prisma directory called “migrations”. You can now update the database with the migration using the command:

npx nx run models:migrate-up

Once you run this, the postgres db which we have running as a docker container will be updated with the latest model. You can connect to your running db using any sql client (I like to use DataGrip from JetBrains). Once you connect, you should see:

Our migration was successful!

Part 4: Generating and using the client

Now that the database is in place, lets generate a prisma client based on our schema that we can use in our application.

npx nx run models:gen-client

Before we can use the generated client you need to export it from the library because it is created within the models lib. Open the <project-root>/libs/models/index.ts and change it so it looks like:

export * from './lib/models.module';
export * from '@prisma/client';

Now all we need to do is use the client in our code:

import { PrismaClient } from '@<your-nx-workspace-name>/models';
const prisma = new PrismaClient()

And that’s it. You can now use prisma in your code. I skipped over a lot details, assuming that you will know what to do. If you get stuck, drop a comment below and I will attempt to assist or update the article (time permitting — with a caveat that I am usually busy during the work week any only check in on medium over the weekends).

The Startup

Get smarter at building your thing. Join The Startup’s +729K followers.