Complete guide to Prisma ORM, PostgreSQL with Neon, migrations, and database management in NextReady.
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL") // Used for migrations
}
model User {
id String @id @default(cuid())
email String @unique
name String?
role UserRole @default(USER)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime? // Soft delete support
// Relations
accounts Account[]
sessions Session[]
files File[]
@@map("users")
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String? @db.Text
access_token String? @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? @db.Text
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
@@map("accounts")
}
model File {
id String @id @default(cuid())
name String
size Int
type String
url String
key String @unique
userId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("files")
}
model EmailQueue {
id String @id @default(cuid())
to String[]
subject String
template String
data Json?
status EmailStatus @default(PENDING)
attempts Int @default(0)
maxAttempts Int @default(3)
scheduledAt DateTime?
sentAt DateTime?
failedAt DateTime?
error String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("email_queue")
}
enum UserRole {
USER
ADMIN
SUPER_ADMIN
}
enum EmailStatus {
PENDING
SENT
FAILED
CANCELLED
}# Quick schema changes
npm run db:push # Push changes instantly
npm run db:studio # Browse data visually
npm run db:seed # Add sample data# Production-safe migrations
npm run db:migrate # Generate migration files
npm run db:migrate:prod # Deploy to productionnpm run db:setupComplete database setup with seeding
First-time setup or reset
npm run db:pushPush schema changes to development database
Development workflow
npm run db:migrateGenerate and apply migrations
Production deployments
npm run db:studioOpen Prisma Studio GUI
Database browsing and editing
npm run db:seedRun database seeding scripts
Populate with sample data
npm run db:resetReset database (destructive)
Start fresh (development only)
// scripts/seed.ts
import { PrismaClient, UserRole } from "@prisma/client";
import bcrypt from "bcryptjs";
const prisma = new PrismaClient();
async function main() {
console.log("🌱 Starting database seeding...");
// Create admin user
const adminPassword = await bcrypt.hash("admin123", 12);
const admin = await prisma.user.upsert({
where: { email: "admin@nextready.com" },
update: {},
create: {
email: "admin@nextready.com",
name: "Admin User",
role: UserRole.ADMIN,
password: adminPassword,
},
});
// Create sample users
const sampleUsers = await Promise.all([
prisma.user.create({
data: {
email: "user1@example.com",
name: "John Doe",
role: UserRole.USER,
},
}),
prisma.user.create({
data: {
email: "user2@example.com",
name: "Jane Smith",
role: UserRole.USER,
},
}),
]);
// Create sample files
await prisma.file.createMany({
data: [
{
name: "sample-document.pdf",
size: 1024000,
type: "application/pdf",
url: "https://example.com/sample.pdf",
key: "uploads/sample-document.pdf",
userId: sampleUsers[0].id,
},
{
name: "profile-picture.jpg",
size: 512000,
type: "image/jpeg",
url: "https://example.com/profile.jpg",
key: "uploads/profile-picture.jpg",
userId: sampleUsers[1].id,
},
],
});
console.log("✅ Database seeded successfully!");
console.log(`Created admin user: ${admin.email}`);
console.log(`Created ${sampleUsers.length} sample users`);
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});Your database system is configured and ready. Next, learn about file management and storage systems.