Prisma
Schema Best Practice
@auth/prisma-adapter requires some models for PostgreSQL but some models like Session
, VerificationToken
are unused when using JWT strategy of next-auth. This template pre-deletes them.
prisma
// https://pris.ly/d/prisma-schema
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
previewFeatures = ["fullTextSearchPostgres"]
}
generator erd {
provider = "prisma-erd-generator"
theme = "forest"
output = "ERD.md"
includeRelationFromFields = true
}
// https://authjs.dev/getting-started/adapters/prisma#schema
model Account {
id String @id @default(cuid())
userId String @map("user_id")
type String
provider String
providerAccountId String @map("provider_account_id")
refresh_token String? @db.Text
access_token String? @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? @db.Text
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@unique([provider, providerAccountId])
@@map("accounts")
}
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime? @map("email_verified")
image String?
accounts Account[]
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
// https://authjs.dev/guides/basics/role-based-access-control
role String?
// example model
items Item[]
@@map("users")
}
// example model
model Item {
id String @id @default(cuid())
content String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
userId String @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("items")
}
ER diagram
prisma-erd-generator can generate ERD from the schema. The current template ERD is here.
See Full Code
md
```mermaid
erDiagram
"accounts" {
String id "🗝️"
String user_id
String type
String provider
String provider_account_id
String refresh_token "❓"
String access_token "❓"
Int expires_at "❓"
String token_type "❓"
String scope "❓"
String id_token "❓"
DateTime created_at
DateTime updated_at
}
"users" {
String id "🗝️"
String name "❓"
String email "❓"
DateTime email_verified "❓"
String image "❓"
DateTime created_at
DateTime updated_at
String role "❓"
}
"items" {
String id "🗝️"
String content
String user_id
DateTime created_at
DateTime updated_at
}
"accounts" o|--|| "users" : "user"
"users" o{--}o "accounts" : "accounts"
"users" o{--}o "items" : "items"
"items" o|--|| "users" : "user"
```
Making single client instance in Development Best Practice
In development, prisma requires avoiding multiple Prisma Client instances but Hot Module Replacement creates them. So this template prepares code to resolve this issue.
ts
// https://www.prisma.io/docs/orm/more/help-and-troubleshooting/help-articles/nextjs-prisma-client-dev-practices
import { PrismaClient } from "@prisma/client";
import { createDBUrl } from "../_utils/db";
function prismaClientSingleton() {
return new PrismaClient({
datasources: {
db: {
url: createDBUrl({}),
},
},
});
}
// biome-ignore lint: Do not shadow the global "globalThis" property.
declare const globalThis: {
prismaGlobal: ReturnType<typeof prismaClientSingleton>;
} & typeof global;
export const prisma = globalThis.prismaGlobal ?? prismaClientSingleton();
if (process.env.NODE_ENV !== "production") {
globalThis.prismaGlobal = prisma;
}
> `datasources.db.url` is always set for parallel execution by testing
Observability Best Practice
Prisma provides OpenTelemetry tracing feature. This template uses @prisma/instrumentation
and you can view Prisma Query, Engine, and Database Query on Jeager via otel-collector. Learn more here